From 769bfdc18566263f36b377d101bb7bd08ced4100 Mon Sep 17 00:00:00 2001
From: "Node.js GitHub Bot" <github-bot@iojs.org>
Date: Fri, 13 Dec 2024 16:17:10 +0000
Subject: [PATCH 1/4] deps: update simdjson to 3.11.3

---
 deps/simdjson/simdjson.cpp |   314 +-
 deps/simdjson/simdjson.h   | 30493 ++++++++++++++++++++---------------
 2 files changed, 17749 insertions(+), 13058 deletions(-)

diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp
index d79fc703a815ca..83b5b8a5b34a5a 100644
--- a/deps/simdjson/simdjson.cpp
+++ b/deps/simdjson/simdjson.cpp
@@ -1,4 +1,4 @@
-/* auto-generated on 2024-08-26 09:37:03 -0400. Do not edit! */
+/* auto-generated on 2024-12-12 10:37:26 -0500. Do not edit! */
 /* including simdjson.cpp:  */
 /* begin file simdjson.cpp */
 #define SIMDJSON_SRC_SIMDJSON_CPP
@@ -77,6 +77,19 @@
 #endif
 #endif
 
+#ifdef __has_include
+#if __has_include(<version>)
+#include <version>
+#endif
+#endif
+
+#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#include <utility>
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
+#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
+#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+
 #endif // SIMDJSON_COMPILER_CHECK_H
 /* end file simdjson/compiler_check.h */
 /* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -284,6 +297,45 @@ using std::size_t;
 
 #endif
 
+
+
+#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
+#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#elif defined _WIN32
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#else
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <machine/endian.h>
+#elif defined(sun) || defined(__sun)
+#include <sys/byteorder.h>
+#elif defined(__MVS__)
+#include <sys/endian.h>
+#else
+#ifdef __has_include
+#if __has_include(<endian.h>)
+#include <endian.h>
+#endif //__has_include(<endian.h>)
+#endif //__has_include
+#endif
+#
+#ifndef __BYTE_ORDER__
+// safe choice
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#endif
+#
+#ifndef __ORDER_LITTLE_ENDIAN__
+// safe choice
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#endif
+#
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#else
+#define SIMDJSON_IS_BIG_ENDIAN 1
+#endif
+#endif
+
+
 #endif // SIMDJSON_PORTABILITY_H
 /* end file simdjson/portability.h */
 
@@ -549,7 +601,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
 // Distributed under the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-#pragma once
 
 #ifndef NONSTD_SV_LITE_H_INCLUDED
 #define NONSTD_SV_LITE_H_INCLUDED
@@ -2430,7 +2481,7 @@ struct simdjson_error : public std::exception {
    */
   simdjson_error(error_code error) noexcept : _error{error} { }
   /** The error message */
-  const char *what() const noexcept { return error_message(error()); }
+  const char *what() const noexcept override { return error_message(error()); }
   /** The error code */
   error_code error() const noexcept { return _error; }
 private:
@@ -2662,6 +2713,122 @@ inline const std::string error_message(int error) noexcept;
 #endif // SIMDJSON_ERROR_H
 /* end file simdjson/error.h */
 /* skipped duplicate #include "simdjson/portability.h" */
+/* including simdjson/concepts.h: #include "simdjson/concepts.h" */
+/* begin file simdjson/concepts.h */
+#ifndef SIMDJSON_CONCEPTS_H
+#define SIMDJSON_CONCEPTS_H
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#include <concepts>
+#include <type_traits>
+
+namespace simdjson {
+namespace concepts {
+
+namespace details {
+#define SIMDJSON_IMPL_CONCEPT(name, method)                                    \
+  template <typename T>                                                        \
+  concept supports_##name = !std::is_const_v<T> && requires {                  \
+    typename std::remove_cvref_t<T>::value_type;                               \
+    requires requires(typename std::remove_cvref_t<T>::value_type &&val,       \
+                      T obj) {                                                 \
+      obj.method(std::move(val));                                              \
+      requires !requires { obj = std::move(val); };                            \
+    };                                                                         \
+  };
+
+SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
+SIMDJSON_IMPL_CONCEPT(emplace, emplace)
+SIMDJSON_IMPL_CONCEPT(push_back, push_back)
+SIMDJSON_IMPL_CONCEPT(add, add)
+SIMDJSON_IMPL_CONCEPT(push, push)
+SIMDJSON_IMPL_CONCEPT(append, append)
+SIMDJSON_IMPL_CONCEPT(insert, insert)
+SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
+
+#undef SIMDJSON_IMPL_CONCEPT
+} // namespace details
+
+/// 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>;
+
+/// 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.
@@ -6447,7 +6614,6 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256];
 
 #endif // SIMDJSON_INTERNAL_SIMDPRUNE_TABLES_H
 /* end file simdjson/internal/simdprune_tables.h */
-
 #endif // SIMDJSON_GENERIC_DEPENDENCIES_H
 /* end file simdjson/generic/dependencies.h */
 /* including generic/dependencies.h: #include <generic/dependencies.h> */
@@ -7623,7 +7789,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
 // See issue https://github.com/simdjson/simdjson/issues/1965
 SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long ret;
   // Search the mask data from least significant bit (LSB)
   // to the most significant bit (MSB) for a set bit (1).
@@ -7639,9 +7805,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
   return input_num & (input_num-1);
 }
 
+// We sometimes call leading_zeroes on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
+// (See below.)
+SIMDJSON_NO_SANITIZE_UNDEFINED
 /* result might be undefined when input_num is zero */
 simdjson_inline int leading_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long leading_zero = 0;
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
@@ -7694,7 +7866,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
 #endif
 
 simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   *result = value1 + value2;
   return *result < value1;
 #else
@@ -7811,7 +7983,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace arm64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
 /* end file simdjson/arm64/numberparsing_defs.h */
@@ -7831,7 +8009,7 @@ namespace arm64 {
 namespace {
 namespace simd {
 
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
 namespace {
 // Start of private section with Visual Studio workaround
 
@@ -7940,7 +8118,7 @@ namespace {
     // We return uint32_t instead of uint16_t because that seems to be more efficient for most
     // purposes (cutting it down to uint16_t costs performance in some compilers).
     simdjson_inline uint32_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask =  simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
                                                    0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
 #else
@@ -7971,7 +8149,7 @@ namespace {
     // Splat constructor
     simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
       uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -8065,7 +8243,7 @@ namespace {
       uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
       uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8095,7 +8273,7 @@ namespace {
       uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
       uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8147,7 +8325,7 @@ namespace {
     // Array constructor
     simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3, int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
       int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -8268,7 +8446,7 @@ namespace {
     }
 
     simdjson_inline uint64_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -9428,7 +9606,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -10379,7 +10556,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
 // See issue https://github.com/simdjson/simdjson/issues/1965
 SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long ret;
   // Search the mask data from least significant bit (LSB)
   // to the most significant bit (MSB) for a set bit (1).
@@ -10395,9 +10572,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
   return input_num & (input_num-1);
 }
 
+// We sometimes call leading_zeroes on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
+// (See below.)
+SIMDJSON_NO_SANITIZE_UNDEFINED
 /* result might be undefined when input_num is zero */
 simdjson_inline int leading_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long leading_zero = 0;
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
@@ -10450,7 +10633,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
 #endif
 
 simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   *result = value1 + value2;
   return *result < value1;
 #else
@@ -10567,7 +10750,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace arm64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
 /* end file simdjson/arm64/numberparsing_defs.h */
@@ -10587,7 +10776,7 @@ namespace arm64 {
 namespace {
 namespace simd {
 
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
 namespace {
 // Start of private section with Visual Studio workaround
 
@@ -10696,7 +10885,7 @@ namespace {
     // We return uint32_t instead of uint16_t because that seems to be more efficient for most
     // purposes (cutting it down to uint16_t costs performance in some compilers).
     simdjson_inline uint32_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask =  simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
                                                    0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
 #else
@@ -10727,7 +10916,7 @@ namespace {
     // Splat constructor
     simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
       uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -10821,7 +11010,7 @@ namespace {
       uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
       uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10851,7 +11040,7 @@ namespace {
       uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
       uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10903,7 +11092,7 @@ namespace {
     // Array constructor
     simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3, int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
       int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -11024,7 +11213,7 @@ namespace {
     }
 
     simdjson_inline uint64_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -13977,6 +14166,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
   return arm64::stringparsing::parse_string(src, dst, allow_replacement);
 }
@@ -14115,8 +14305,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
 /* end file simdjson/haswell/intrinsics.h */
 
 #if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+// We enable bmi2 only if LLVM/clang is used, because GCC may not
+// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
+#if defined(__clang__)
+SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
+#else
 SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
 #endif
+#endif
 
 /* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
 /* begin file simdjson/haswell/bitmanipulation.h */
@@ -15770,7 +15966,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -16748,8 +16943,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
 /* end file simdjson/haswell/intrinsics.h */
 
 #if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+// We enable bmi2 only if LLVM/clang is used, because GCC may not
+// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
+#if defined(__clang__)
+SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
+#else
 SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
 #endif
+#endif
 
 /* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
 /* begin file simdjson/haswell/bitmanipulation.h */
@@ -20193,6 +20394,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
   return haswell::stringparsing::parse_string(src, dst, replacement_char);
 }
@@ -21984,7 +22186,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -26448,6 +26649,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
   return icelake::stringparsing::parse_string(src, dst, replacement_char);
 }
@@ -26750,7 +26952,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace ppc64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
 /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -28354,7 +28562,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -29494,7 +29701,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace ppc64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
 /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -32861,6 +33074,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
   return ppc64::stringparsing::parse_string(src, dst, replacement_char);
 }
@@ -35090,7 +35304,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -39950,6 +40163,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
   return westmere::stringparsing::parse_string(src, dst, replacement_char);
 }
@@ -40176,7 +40390,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lsx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lsx/numberparsing_defs.h */
@@ -41650,7 +41870,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -42705,7 +42924,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lsx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lsx/numberparsing_defs.h */
@@ -45936,6 +46161,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
   return lsx::stringparsing::parse_string(src, dst, allow_replacement);
 }
@@ -46159,7 +46385,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lasx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lasx/numberparsing_defs.h */
@@ -47649,7 +47881,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -48704,7 +48935,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lasx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lasx/numberparsing_defs.h */
@@ -51947,6 +52184,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
   return lasx::stringparsing::parse_string(src, dst, allow_replacement);
 }
@@ -52188,7 +52426,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace fallback
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
 /* end file simdjson/fallback/numberparsing_defs.h */
@@ -53247,7 +53491,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -54322,7 +54565,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace fallback
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
 /* end file simdjson/fallback/numberparsing_defs.h */
@@ -55909,6 +56158,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
   return stage2::tape_builder::parse_document<true>(*this, _doc);
 }
 
+SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
   return fallback::stringparsing::parse_string(src, dst, replacement_char);
 }
diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index f21cd9381eef59..c80e8cdafc47b0 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -1,4 +1,4 @@
-/* auto-generated on 2024-08-26 09:37:03 -0400. Do not edit! */
+/* auto-generated on 2024-12-12 10:37:26 -0500. Do not edit! */
 /* including simdjson.h:  */
 /* begin file simdjson.h */
 #ifndef SIMDJSON_H
@@ -97,6 +97,19 @@
 #endif
 #endif
 
+#ifdef __has_include
+#if __has_include(<version>)
+#include <version>
+#endif
+#endif
+
+#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#include <utility>
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
+#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
+#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+
 #endif // SIMDJSON_COMPILER_CHECK_H
 /* end file simdjson/compiler_check.h */
 /* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -304,6 +317,45 @@ using std::size_t;
 
 #endif
 
+
+
+#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
+#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#elif defined _WIN32
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#else
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <machine/endian.h>
+#elif defined(sun) || defined(__sun)
+#include <sys/byteorder.h>
+#elif defined(__MVS__)
+#include <sys/endian.h>
+#else
+#ifdef __has_include
+#if __has_include(<endian.h>)
+#include <endian.h>
+#endif //__has_include(<endian.h>)
+#endif //__has_include
+#endif
+#
+#ifndef __BYTE_ORDER__
+// safe choice
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#endif
+#
+#ifndef __ORDER_LITTLE_ENDIAN__
+// safe choice
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#endif
+#
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define SIMDJSON_IS_BIG_ENDIAN 0
+#else
+#define SIMDJSON_IS_BIG_ENDIAN 1
+#endif
+#endif
+
+
 #endif // SIMDJSON_PORTABILITY_H
 /* end file simdjson/portability.h */
 
@@ -569,7 +621,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
 // Distributed under the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-#pragma once
 
 #ifndef NONSTD_SV_LITE_H_INCLUDED
 #define NONSTD_SV_LITE_H_INCLUDED
@@ -2370,7 +2421,7 @@ namespace std {
 #define SIMDJSON_SIMDJSON_VERSION_H
 
 /** The version of simdjson being used (major.minor.revision) */
-#define SIMDJSON_VERSION "3.10.1"
+#define SIMDJSON_VERSION "3.11.3"
 
 namespace simdjson {
 enum {
@@ -2381,11 +2432,11 @@ enum {
   /**
    * The minor version (major.MINOR.revision) of simdjson being used.
    */
-  SIMDJSON_VERSION_MINOR = 10,
+  SIMDJSON_VERSION_MINOR = 11,
   /**
    * The revision (major.minor.REVISION) of simdjson being used.
    */
-  SIMDJSON_VERSION_REVISION = 1
+  SIMDJSON_VERSION_REVISION = 3
 };
 } // namespace simdjson
 
@@ -2493,7 +2544,7 @@ struct simdjson_error : public std::exception {
    */
   simdjson_error(error_code error) noexcept : _error{error} { }
   /** The error message */
-  const char *what() const noexcept { return error_message(error()); }
+  const char *what() const noexcept override { return error_message(error()); }
   /** The error code */
   error_code error() const noexcept { return _error; }
 private:
@@ -2725,6 +2776,122 @@ inline const std::string error_message(int error) noexcept;
 #endif // SIMDJSON_ERROR_H
 /* end file simdjson/error.h */
 /* skipped duplicate #include "simdjson/portability.h" */
+/* including simdjson/concepts.h: #include "simdjson/concepts.h" */
+/* begin file simdjson/concepts.h */
+#ifndef SIMDJSON_CONCEPTS_H
+#define SIMDJSON_CONCEPTS_H
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#include <concepts>
+#include <type_traits>
+
+namespace simdjson {
+namespace concepts {
+
+namespace details {
+#define SIMDJSON_IMPL_CONCEPT(name, method)                                    \
+  template <typename T>                                                        \
+  concept supports_##name = !std::is_const_v<T> && requires {                  \
+    typename std::remove_cvref_t<T>::value_type;                               \
+    requires requires(typename std::remove_cvref_t<T>::value_type &&val,       \
+                      T obj) {                                                 \
+      obj.method(std::move(val));                                              \
+      requires !requires { obj = std::move(val); };                            \
+    };                                                                         \
+  };
+
+SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
+SIMDJSON_IMPL_CONCEPT(emplace, emplace)
+SIMDJSON_IMPL_CONCEPT(push_back, push_back)
+SIMDJSON_IMPL_CONCEPT(add, add)
+SIMDJSON_IMPL_CONCEPT(push, push)
+SIMDJSON_IMPL_CONCEPT(append, append)
+SIMDJSON_IMPL_CONCEPT(insert, insert)
+SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
+
+#undef SIMDJSON_IMPL_CONCEPT
+} // namespace details
+
+/// 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>;
+
+/// 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.
@@ -3655,9 +3822,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
 } // namespace simdjson
 
 // This is deliberately outside of simdjson so that people get it without having to use the namespace
-inline simdjson::padded_string operator "" _padded(const char *str, size_t len);
+inline simdjson::padded_string operator ""_padded(const char *str, size_t len);
 #ifdef __cpp_char8_t
-inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len);
+inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len);
 #endif
 
 namespace simdjson {
@@ -3796,6 +3963,15 @@ class padded_string_view : public std::string_view {
 inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false);
 #endif
 
+/**
+ * Create a padded_string_view from a string. The string will be padded with SIMDJSON_PADDING
+ * space characters. The resulting padded_string_view will have a length equal to the original
+ * string.
+ *
+ * @param s The string.
+ * @return The padded string.
+ */
+inline padded_string_view pad(std::string& s) noexcept;
 } // namespace simdjson
 
 #endif // SIMDJSON_PADDED_STRING_VIEW_H
@@ -3859,6 +4035,11 @@ inline bool padded_string_view::remove_utf8_bom() noexcept {
 inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
 #endif
 
+inline padded_string_view pad(std::string& s) noexcept {
+  const auto len = s.size();
+  s.append(SIMDJSON_PADDING, ' ');
+  return padded_string_view(s.data(), len, s.size());
+}
 } // namespace simdjson
 
 
@@ -3911,6 +4092,9 @@ inline padded_string::padded_string(const char *data, size_t length) noexcept
   if ((data != nullptr) && (data_ptr != nullptr)) {
     std::memcpy(data_ptr, data, length);
   }
+  if (data_ptr == nullptr) {
+    viable_size = 0;
+  }
 }
 #ifdef __cpp_char8_t
 inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
@@ -3918,12 +4102,17 @@ inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
   if ((data != nullptr) && (data_ptr != nullptr)) {
     std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
   }
+  if (data_ptr == nullptr) {
+    viable_size = 0;
+  }
 }
 #endif
 // note: do not pass std::string arguments by value
 inline padded_string::padded_string(const std::string & str_ ) noexcept
     : viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
-  if (data_ptr != nullptr) {
+  if (data_ptr == nullptr) {
+    viable_size = 0;
+  } else {
     std::memcpy(data_ptr, str_.data(), str_.size());
   }
 }
@@ -4037,11 +4226,11 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
 
 } // namespace simdjson
 
-inline simdjson::padded_string operator "" _padded(const char *str, size_t len) {
+inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
   return simdjson::padded_string(str, len);
 }
 #ifdef __cpp_char8_t
-inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len) {
+inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len) {
   return simdjson::padded_string(reinterpret_cast<const char8_t *>(str), len);
 }
 #endif
@@ -4275,6 +4464,21 @@ class array {
    */
   inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
 
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
+
   /**
    * Get the value at the given index. This function has linear-time complexity and
    * is equivalent to the following:
@@ -4319,6 +4523,7 @@ struct simdjson_result<dom::array> : public internal::simdjson_result_base<dom::
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
 
   inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
+  inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
   inline simdjson_result<dom::element> at(size_t index) const noexcept;
 
 #if SIMDJSON_EXCEPTIONS
@@ -4654,6 +4859,22 @@ class parser {
    *   simdjson::dom::parser parser;
    *   simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's parse function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    element doc = parser.parse(simdjson::pad(json));
+   *
    * ### Parser Capacity
    *
    * If the parser's current capacity is less than len, it will allocate enough capacity
@@ -5001,9 +5222,14 @@ class parser {
   /**
    * The parser instance can use threads when they are available to speed up some
    * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * behavior of the parser for future operations. Set to true by default.
    */
   bool threaded{true};
+#else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
 #endif
   /** @private Use the new DOM API instead */
   class Iterator;
@@ -5796,6 +6022,8 @@ class element {
    *         - INCORRECT_TYPE if this is not an object
    */
   inline simdjson_result<element> operator[](const char *key) const noexcept;
+  simdjson_result<element> operator[](int) const noexcept = delete;
+
 
   /**
    * Get the value associated with the given JSON pointer.  We use the RFC 6901
@@ -5821,6 +6049,21 @@ class element {
    */
   inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
 
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
+
 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
   /**
    *
@@ -5949,7 +6192,9 @@ struct simdjson_result<dom::element> : public internal::simdjson_result_base<dom
 
   simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
   simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
+  simdjson_result<dom::element> operator[](int) const noexcept = delete;
   simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
+  simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
   [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
   simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
   simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept;
@@ -6124,6 +6369,7 @@ class object {
    *         - INCORRECT_TYPE if this is not an object
    */
   inline simdjson_result<element> operator[](const char *key) const noexcept;
+  simdjson_result<element> operator[](int) const noexcept = delete;
 
   /**
    * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -6150,6 +6396,21 @@ class object {
    */
   inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
 
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
+
   /**
    * Get the value associated with the given key.
    *
@@ -6222,7 +6483,9 @@ struct simdjson_result<dom::object> : public internal::simdjson_result_base<dom:
 
   inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
   inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
+  simdjson_result<dom::element> operator[](int) const noexcept = delete;
   inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
+  inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
   inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
   inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
 
@@ -6529,6 +6792,73 @@ std::string prettify(simdjson_result<T> x) {
 /* skipped duplicate #include "simdjson/dom/array.h" */
 /* skipped duplicate #include "simdjson/dom/element.h" */
 /* skipped duplicate #include "simdjson/error-inl.h" */
+/* including simdjson/jsonpathutil.h: #include "simdjson/jsonpathutil.h" */
+/* begin file simdjson/jsonpathutil.h */
+#ifndef SIMDJSON_JSONPATHUTIL_H
+#define SIMDJSON_JSONPATHUTIL_H
+
+#include <string>
+#include <string_view>
+
+namespace simdjson {
+/**
+ * Converts JSONPath to JSON Pointer.
+ * @param json_path The JSONPath string to be converted.
+ * @return A string containing the equivalent JSON Pointer.
+ */
+inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
+  size_t i = 0;
+
+  // if JSONPath starts with $, skip it
+  if (!json_path.empty() && json_path.front() == '$') {
+    i = 1;
+  }
+  if (json_path.empty() || (json_path[i] != '.' &&
+      json_path[i] != '[')) {
+    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+  }
+
+  std::string result;
+  // Reserve space to reduce allocations, adjusting for potential increases due
+  // to escaping.
+  result.reserve(json_path.size() * 2);
+
+  while (i < json_path.length()) {
+    if (json_path[i] == '.') {
+      result += '/';
+    } else if (json_path[i] == '[') {
+      result += '/';
+      ++i; // Move past the '['
+      while (i < json_path.length() && json_path[i] != ']') {
+          if (json_path[i] == '~') {
+            result += "~0";
+          } else if (json_path[i] == '/') {
+            result += "~1";
+          } else {
+            result += json_path[i];
+          }
+          ++i;
+      }
+      if (i == json_path.length() || json_path[i] != ']') {
+          return "-1"; // Using sentinel value that will be handled as an error by the caller.
+      }
+    } else {
+      if (json_path[i] == '~') {
+          result += "~0";
+      } else if (json_path[i] == '/') {
+          result += "~1";
+      } else {
+          result += json_path[i];
+      }
+    }
+    ++i;
+  }
+
+  return result;
+}
+} // namespace simdjson
+#endif // SIMDJSON_JSONPATHUTIL_H
+/* end file simdjson/jsonpathutil.h */
 /* including simdjson/internal/tape_ref-inl.h: #include "simdjson/internal/tape_ref-inl.h" */
 /* begin file simdjson/internal/tape_ref-inl.h */
 #ifndef SIMDJSON_TAPE_REF_INL_H
@@ -6716,6 +7046,13 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
+
+ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+ }
+
 inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
   if (error()) { return error(); }
   return first.at(index);
@@ -6785,6 +7122,12 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
   return child;
 }
 
+inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
 inline simdjson_result<element> array::at(size_t index) const noexcept {
   SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
   size_t i=0;
@@ -6861,6 +7204,7 @@ inline bool array::iterator::operator>(const array::iterator& other) const noexc
 
 /* skipped duplicate #include "simdjson/dom/element-inl.h" */
 /* skipped duplicate #include "simdjson/error-inl.h" */
+/* skipped duplicate #include "simdjson/jsonpathutil.h" */
 
 #include <cstring>
 
@@ -6888,6 +7232,11 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(st
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
+inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
 inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
   if (error()) { return error(); }
   return first.at_key(key);
@@ -6985,6 +7334,12 @@ inline simdjson_result<element> object::at_pointer(std::string_view json_pointer
   return child;
 }
 
+inline simdjson_result<element> object::at_path(std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
 inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
   iterator end_field = end();
   for (iterator field = begin(); field != end_field; ++field) {
@@ -7117,6 +7472,7 @@ static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::
 #endif // SIMDJSON_OBJECT_INL_H
 /* end file simdjson/dom/object-inl.h */
 /* skipped duplicate #include "simdjson/error-inl.h" */
+/* skipped duplicate #include "simdjson/jsonpathutil.h" */
 
 #include <ostream>
 #include <limits>
@@ -7230,6 +7586,11 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
+simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_path(const std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
 [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
@@ -7520,6 +7881,11 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
     }
   }
 }
+inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
 [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
 inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept {
@@ -9424,7 +9790,6 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256];
 
 #endif // SIMDJSON_INTERNAL_SIMDPRUNE_TABLES_H
 /* end file simdjson/internal/simdprune_tables.h */
-
 #endif // SIMDJSON_GENERIC_DEPENDENCIES_H
 /* end file simdjson/generic/dependencies.h */
 
@@ -9838,7 +10203,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
 // See issue https://github.com/simdjson/simdjson/issues/1965
 SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long ret;
   // Search the mask data from least significant bit (LSB)
   // to the most significant bit (MSB) for a set bit (1).
@@ -9854,9 +10219,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
   return input_num & (input_num-1);
 }
 
+// We sometimes call leading_zeroes on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
+// (See below.)
+SIMDJSON_NO_SANITIZE_UNDEFINED
 /* result might be undefined when input_num is zero */
 simdjson_inline int leading_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long leading_zero = 0;
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
@@ -9909,7 +10280,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
 #endif
 
 simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   *result = value1 + value2;
   return *result < value1;
 #else
@@ -10026,7 +10397,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace arm64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
 /* end file simdjson/arm64/numberparsing_defs.h */
@@ -10046,7 +10423,7 @@ namespace arm64 {
 namespace {
 namespace simd {
 
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
 namespace {
 // Start of private section with Visual Studio workaround
 
@@ -10155,7 +10532,7 @@ namespace {
     // We return uint32_t instead of uint16_t because that seems to be more efficient for most
     // purposes (cutting it down to uint16_t costs performance in some compilers).
     simdjson_inline uint32_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask =  simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
                                                    0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
 #else
@@ -10186,7 +10563,7 @@ namespace {
     // Splat constructor
     simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
       uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -10280,7 +10657,7 @@ namespace {
       uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
       uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10310,7 +10687,7 @@ namespace {
       uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
       uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10362,7 +10739,7 @@ namespace {
     // Array constructor
     simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3, int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
       int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -10483,7 +10860,7 @@ namespace {
     }
 
     simdjson_inline uint64_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -11643,7 +12020,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -12687,7 +13063,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace fallback
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
 /* end file simdjson/fallback/numberparsing_defs.h */
@@ -13746,7 +14128,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -14686,8 +15067,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
 /* end file simdjson/haswell/intrinsics.h */
 
 #if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+// We enable bmi2 only if LLVM/clang is used, because GCC may not
+// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
+#if defined(__clang__)
+SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
+#else
 SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
 #endif
+#endif
 
 /* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
 /* begin file simdjson/haswell/bitmanipulation.h */
@@ -16341,7 +16728,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -18935,7 +19321,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -20040,7 +20425,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace ppc64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
 /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -21644,7 +22035,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -24676,7 +25066,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -25705,7 +26094,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lsx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lsx/numberparsing_defs.h */
@@ -27179,7 +27574,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -28205,7 +28599,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lasx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lasx/numberparsing_defs.h */
@@ -29695,7 +30095,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
 // Our objective is accurate parsing (ULP of 0) at high speed.
 template<typename W>
 simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
-
   //
   // Check for minus sign
   //
@@ -30566,6 +30965,7 @@ simdjson_inline implementation_simdjson_result_base<T>::implementation_simdjson_
 /* skipped duplicate #include "simdjson/padded_string.h" */
 /* skipped duplicate #include "simdjson/padded_string_view.h" */
 /* skipped duplicate #include "simdjson/internal/dom_parser_implementation.h" */
+/* skipped duplicate #include "simdjson/jsonpathutil.h" */
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H
 /* end file simdjson/generic/ondemand/dependencies.h */
@@ -30652,7 +31052,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
 // See issue https://github.com/simdjson/simdjson/issues/1965
 SIMDJSON_NO_SANITIZE_MEMORY
 simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long ret;
   // Search the mask data from least significant bit (LSB)
   // to the most significant bit (MSB) for a set bit (1).
@@ -30668,9 +31068,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
   return input_num & (input_num-1);
 }
 
+// We sometimes call leading_zeroes on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
+// (See below.)
+SIMDJSON_NO_SANITIZE_UNDEFINED
 /* result might be undefined when input_num is zero */
 simdjson_inline int leading_zeroes(uint64_t input_num) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   unsigned long leading_zero = 0;
   // Search the mask data from most significant bit (MSB)
   // to least significant bit (LSB) for a set bit (1).
@@ -30723,7 +31129,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
 #endif
 
 simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
   *result = value1 + value2;
   return *result < value1;
 #else
@@ -30840,7 +31246,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace arm64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
 /* end file simdjson/arm64/numberparsing_defs.h */
@@ -30860,7 +31272,7 @@ namespace arm64 {
 namespace {
 namespace simd {
 
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
 namespace {
 // Start of private section with Visual Studio workaround
 
@@ -30969,7 +31381,7 @@ namespace {
     // We return uint32_t instead of uint16_t because that seems to be more efficient for most
     // purposes (cutting it down to uint16_t costs performance in some compilers).
     simdjson_inline uint32_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask =  simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
                                                    0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
 #else
@@ -31000,7 +31412,7 @@ namespace {
     // Splat constructor
     simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
       uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
@@ -31094,7 +31506,7 @@ namespace {
       uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
       uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -31124,7 +31536,7 @@ namespace {
       uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
       uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
       // we increment by 0x08 the second half of the mask
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
 #else
       uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -31176,7 +31588,7 @@ namespace {
     // Array constructor
     simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
     // Member-by-member initialization
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
     simdjson_inline simd8(
       int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3, int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
       int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
@@ -31297,7 +31709,7 @@ namespace {
     }
 
     simdjson_inline uint64_t to_bitmask() const {
-#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
       const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
         0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -31460,6 +31872,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for arm64 */
+/* including simdjson/generic/ondemand/deserialize.h for arm64: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for arm64 */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<arm64::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<arm64::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<arm64::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<arm64::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = arm64::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = arm64::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = arm64::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = arm64::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = arm64::ondemand::value;
+  using document_type = arm64::ondemand::document;
+  using document_reference_type = arm64::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for arm64 */
 /* including simdjson/generic/ondemand/value_iterator.h for arm64: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for arm64 */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -31964,12 +32502,15 @@ struct simdjson_result<arm64::ondemand::value_iterator> : public arm64::implemen
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace arm64 {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -31994,16 +32535,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -32013,7 +32559,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -32089,6 +32660,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -32340,6 +32922,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -32707,6 +33290,7 @@ struct simdjson_result<arm64::ondemand::value> : public arm64::implementation_si
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<arm64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<arm64::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -33762,6 +34346,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -33956,8 +34556,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -34099,7 +34703,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -34377,8 +34982,11 @@ struct simdjson_result<arm64::ondemand::array_iterator> : public arm64::implemen
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace arm64 {
 namespace ondemand {
@@ -34551,24 +35159,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -34582,7 +35205,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -34684,7 +35332,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -34796,6 +35445,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -35064,6 +35714,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -35089,7 +35744,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -35114,6 +35832,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -35192,6 +35911,7 @@ struct simdjson_result<arm64::ondemand::document> : public arm64::implementation
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<arm64::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::json_type> type() noexcept;
@@ -35241,8 +35961,14 @@ struct simdjson_result<arm64::ondemand::document_reference> : public arm64::impl
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, arm64::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator arm64::ondemand::array() & noexcept(false);
   simdjson_inline operator arm64::ondemand::object() & noexcept(false);
@@ -35263,6 +35989,7 @@ struct simdjson_result<arm64::ondemand::document_reference> : public arm64::impl
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<arm64::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<arm64::ondemand::json_type> type() noexcept;
@@ -36193,6 +36920,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for arm64 */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for arm64: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for arm64 */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  arm64::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for arm64 */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for arm64: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for arm64 */
@@ -36200,6 +37098,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -36361,53 +37260,6 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
   return child;
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
-  }
-
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
-
-  size_t i = 0;
-
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
-  }
-
-  return result;
-}
-
 inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
   auto json_pointer = json_path_to_pointer_conversion(json_path);
   if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
@@ -36561,313 +37413,276 @@ simdjson_inline simdjson_result<arm64::ondemand::array_iterator> &simdjson_resul
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/array_iterator-inl.h for arm64 */
-/* including simdjson/generic/ondemand/document-inl.h for arm64: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for arm64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* including simdjson/generic/ondemand/value-inl.h for arm64: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for arm64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace arm64 {
 namespace ondemand {
 
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
 {
-  logger::log_start_value(iter, "document");
 }
-
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
 }
-
-inline void document::rewind() noexcept {
-  iter.rewind();
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
 }
-
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
 }
-
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
 }
 
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
 }
-
-
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
 }
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
 }
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
 }
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
-    return get_object();
-  } else {
-    return object::resume(resume_value_iterator());
-  }
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
 }
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
-
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
-  }
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
 }
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
 }
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
 }
-
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
-
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
 }
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
 }
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
 }
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
 }
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
 }
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
 }
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
 }
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
 }
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
 }
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
 }
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
-
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
-
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
 }
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
 }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
-
-#endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
   auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
   return answer;
 }
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
   auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
+  answer = a.count_fields();
+  iter.move_at_start();
   return answer;
 }
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
   auto a = get_array();
   return a.at(index);
 }
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
-}
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
   return start_or_resume_object()[key];
 }
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
   return start_or_resume_object()[key];
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
-}
-
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return (this_type == json_type::string);
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
-}
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
 }
 
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
 }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
+
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
   }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t)
@@ -36877,15 +37692,15 @@ simdjson_inline simdjson_result<value> document::at_pointer(std::string_view jso
     case json_type::object:
       return (*this).get_object().at_pointer(json_pointer);
     default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
       return INVALID_JSON_POINTER;
   }
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t) {
@@ -36904,614 +37719,1253 @@ simdjson_inline simdjson_result<value> document::at_path(std::string_view json_p
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<arm64::ondemand::document>::simdjson_result(
-  arm64::ondemand::document &&value
+simdjson_inline simdjson_result<arm64::ondemand::value>::simdjson_result(
+  arm64::ondemand::value &&value
 ) noexcept :
-    implementation_simdjson_result_base<arm64::ondemand::document>(
-      std::forward<arm64::ondemand::document>(value)
+    implementation_simdjson_result_base<arm64::ondemand::value>(
+      std::forward<arm64::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::simdjson_result(
+simdjson_inline simdjson_result<arm64::ondemand::value>::simdjson_result(
   error_code error
 ) noexcept :
-    implementation_simdjson_result_base<arm64::ondemand::document>(
-      error
-    )
+    implementation_simdjson_result_base<arm64::ondemand::value>(error)
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document>::count_elements() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::value>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::value>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at(size_t index) noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline error_code simdjson_result<arm64::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document>::begin() & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document>::end() & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
   return {};
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::operator[](std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
-simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::document>::get_array() & noexcept {
+
+simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::value>::get_array() noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::document>::get_object() & noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::value>::get_object() noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::value>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::value>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::value>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::value>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::value>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::value>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::document>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::value>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document>::get() & noexcept {
+template<> simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get<arm64::ondemand::value>(arm64::ondemand::value &out) noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  out = first;
+  return SUCCESS;
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document>::get() && noexcept {
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::value>::get() noexcept {
   if (error()) { return error(); }
-  return std::forward<arm64::ondemand::document>(first).get<T>();
+  return first.get<T>();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get(T &out) & noexcept {
+template<typename T> simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get(T &out) noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<arm64::ondemand::document>(first).get<T>(out);
-}
 
-template<> simdjson_inline simdjson_result<arm64::ondemand::document> simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<arm64::ondemand::document> simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<arm64::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>(arm64::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>(arm64::ondemand::document &out) && noexcept {
+template<> simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::get<arm64::ondemand::value>() noexcept  {
   if (error()) { return error(); }
-  out = std::forward<arm64::ondemand::document>(first);
-  return SUCCESS;
+  return std::move(first);
 }
 
-simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::document>::type() noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::value>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_string() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-
-simdjson_inline bool simdjson_result<arm64::ondemand::document>::is_negative() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_integer() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-
-simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::document>::get_number_type() noexcept {
+simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::value>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-
-simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::document>::get_number() noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::value>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
-
-
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, arm64::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::array() & noexcept(false) {
+template <class T>
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::object() & noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::array() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::object() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::value() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::value>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-
-simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::document>::current_location() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.raw_json_token();
 }
 
-simdjson_inline bool simdjson_result<arm64::ondemand::document>::at_end() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first.at_end();
+  return first.raw_json();
 }
 
-
-simdjson_inline int32_t simdjson_result<arm64::ondemand::document>::current_depth() const noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<int32_t> simdjson_result<arm64::ondemand::value>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for arm64 */
+/* including simdjson/generic/ondemand/document-inl.h for arm64: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for arm64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace arm64 {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace arm64
-} // namespace simdjson
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
+{
+  logger::log_start_value(iter, "document");
+}
 
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
+}
 
+inline void document::rewind() noexcept {
+  iter.rewind();
+}
 
-namespace simdjson {
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::simdjson_result(arm64::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<arm64::ondemand::document_reference>(std::forward<arm64::ondemand::document_reference>(value), error) {}
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
+}
 
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
+}
 
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
 }
-simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
 }
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
 }
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document_reference>::end() & noexcept {
-  return {};
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
+    return get_object();
+  } else {
+    return object::resume(resume_value_iterator());
+  }
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
+
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
 }
-simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::document_reference>::get_object() & noexcept {
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
+}
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
+}
+
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
+
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
+}
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
+
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
+
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
+
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
+
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
+
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
+}
+
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+}
+
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace arm64
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<arm64::ondemand::document>::simdjson_result(
+  arm64::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<arm64::ondemand::document>(
+      std::forward<arm64::ondemand::document>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<arm64::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<arm64::ondemand::document>(
+      error
+    )
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<arm64::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document_reference>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document_reference>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document_reference>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document_reference>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document_reference>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document_reference>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::document_reference>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::document>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::get_value() noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
   return first.get_value();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
-simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::document_reference>::type() noexcept {
+
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<arm64::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<arm64::ondemand::document>(first).get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<arm64::ondemand::document> simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<arm64::ondemand::document> simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<arm64::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>(arm64::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<arm64::ondemand::document>::get<arm64::ondemand::document>(arm64::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<arm64::ondemand::document>(first);
+  return SUCCESS;
+}
+
+simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_scalar() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_string() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<arm64::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::document_reference>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::document_reference>::get_number() noexcept {
+
+simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, arm64::ondemand::document_reference>::value == false>::type>
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator T() noexcept(false) {
+template <class T, typename std::enable_if<std::is_same<T, arm64::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::array() & noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::object() & noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::value() noexcept(false) {
+simdjson_inline simdjson_result<arm64::ondemand::document>::operator arm64::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::document_reference>::current_location() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::raw_json_token() noexcept {
+simdjson_inline bool simdjson_result<arm64::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
+}
+
+
+simdjson_inline int32_t simdjson_result<arm64::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
   return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for arm64 */
-/* including simdjson/generic/ondemand/document_stream-inl.h for arm64: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for arm64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <algorithm>
-#include <stdexcept>
 
 namespace simdjson {
 namespace arm64 {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
+} // namespace ondemand
+} // namespace arm64
+} // namespace simdjson
 
-inline stage1_worker::~stage1_worker() {
+
+
+namespace simdjson {
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::simdjson_result(arm64::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<arm64::ondemand::document_reference>(std::forward<arm64::ondemand::document_reference>(value), error) {}
+
+
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::document_reference>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<arm64::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<arm64::ondemand::document_reference>(first).get<T>(out);
+}
+simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get(arm64::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<arm64::ondemand::document_reference>::get(arm64::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, arm64::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, arm64::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<arm64::ondemand::document_reference>::operator arm64::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for arm64 */
+/* including simdjson/generic/ondemand/document_stream-inl.h for arm64: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for arm64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace simdjson {
+namespace arm64 {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
+}
+
+inline stage1_worker::~stage1_worker() {
   // The thread may never outlive the stage1_worker instance
   // and will always be stopped/joined before the stage1_worker
   // instance is gone.
@@ -37637,7 +39091,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -40011,551 +41464,6 @@ simdjson_inline simdjson_result<arm64::ondemand::token_iterator>::simdjson_resul
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/token_iterator-inl.h for arm64 */
-/* including simdjson/generic/ondemand/value-inl.h for arm64: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for arm64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace arm64 {
-namespace ondemand {
-
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace arm64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<arm64::ondemand::value>::simdjson_result(
-  arm64::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<arm64::ondemand::value>(
-      std::forward<arm64::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<arm64::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<arm64::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<arm64::ondemand::array_iterator> simdjson_result<arm64::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::array> simdjson_result<arm64::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<arm64::ondemand::object> simdjson_result<arm64::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<arm64::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<arm64::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<arm64::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<arm64::ondemand::raw_json_string> simdjson_result<arm64::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<arm64::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-
-template<> simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::get<arm64::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-template<> simdjson_inline error_code simdjson_result<arm64::ondemand::value>::get<arm64::ondemand::value>(arm64::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::json_type> simdjson_result<arm64::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<arm64::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<arm64::number_type> simdjson_result<arm64::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<arm64::ondemand::number> simdjson_result<arm64::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator arm64::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<arm64::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<arm64::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-
-simdjson_inline simdjson_result<const char *> simdjson_result<arm64::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline simdjson_result<int32_t> simdjson_result<arm64::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<arm64::ondemand::value> simdjson_result<arm64::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for arm64 */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for arm64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for arm64 */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -41359,6 +42267,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -41650,6 +42560,8 @@ simdjson_inline simdjson_result<arm64::ondemand::value_iterator>::simdjson_resul
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for arm64 */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for arm64 */
 /* including simdjson/arm64/end.h: #include "simdjson/arm64/end.h" */
 /* begin file simdjson/arm64/end.h */
@@ -41865,7 +42777,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace fallback
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
 /* end file simdjson/fallback/numberparsing_defs.h */
@@ -41927,6 +42845,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for fallback */
+/* including simdjson/generic/ondemand/deserialize.h for fallback: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for fallback */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<fallback::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<fallback::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<fallback::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<fallback::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = fallback::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = fallback::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = fallback::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = fallback::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = fallback::ondemand::value;
+  using document_type = fallback::ondemand::document;
+  using document_reference_type = fallback::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for fallback */
 /* including simdjson/generic/ondemand/value_iterator.h for fallback: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for fallback */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -42431,12 +43475,15 @@ struct simdjson_result<fallback::ondemand::value_iterator> : public fallback::im
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace fallback {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -42461,16 +43508,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -42480,7 +43532,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -42556,6 +43633,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -42807,6 +43895,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -43174,6 +44263,7 @@ struct simdjson_result<fallback::ondemand::value> : public fallback::implementat
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<fallback::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<fallback::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -44229,6 +45319,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -44423,8 +45529,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -44566,7 +45676,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -44844,8 +45955,11 @@ struct simdjson_result<fallback::ondemand::array_iterator> : public fallback::im
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
@@ -45018,24 +46132,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -45049,7 +46178,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -45151,7 +46305,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -45263,6 +46418,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -45531,6 +46687,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -45556,7 +46717,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -45581,6 +46805,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -45659,6 +46884,7 @@ struct simdjson_result<fallback::ondemand::document> : public fallback::implemen
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<fallback::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::json_type> type() noexcept;
@@ -45708,8 +46934,14 @@ struct simdjson_result<fallback::ondemand::document_reference> : public fallback
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator fallback::ondemand::array() & noexcept(false);
   simdjson_inline operator fallback::ondemand::object() & noexcept(false);
@@ -45730,6 +46962,7 @@ struct simdjson_result<fallback::ondemand::document_reference> : public fallback
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<fallback::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<fallback::ondemand::json_type> type() noexcept;
@@ -46660,6 +47893,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for fallback */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for fallback: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for fallback */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  fallback::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for fallback */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for fallback: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for fallback */
@@ -46667,6 +48071,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -46779,115 +48184,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::array>::simdjson_result(
+  fallback::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::array>(
+      std::forward<fallback::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<fallback::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<fallback::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<fallback::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<fallback::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for fallback */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator>::simdjson_result(
+  fallback::ondemand::array_iterator &&value
+) noexcept
+  : fallback::implementation_simdjson_result_base<fallback::ondemand::array_iterator>(std::forward<fallback::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : fallback::implementation_simdjson_result_base<fallback::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<fallback::ondemand::array_iterator>::operator==(const simdjson_result<fallback::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<fallback::ondemand::array_iterator>::operator!=(const simdjson_result<fallback::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> &simdjson_result<fallback::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/value-inl.h for fallback: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -46896,138 +48692,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::array>::simdjson_result(
-  fallback::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::array>(
-      std::forward<fallback::ondemand::array>(value)
+simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
+  fallback::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::value>(
+      std::forward<fallback::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<fallback::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<fallback::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<fallback::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<fallback::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for fallback */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>(fallback::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator>::simdjson_result(
-  fallback::ondemand::array_iterator &&value
-) noexcept
-  : fallback::implementation_simdjson_result_base<fallback::ondemand::array_iterator>(std::forward<fallback::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : fallback::implementation_simdjson_result_base<fallback::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<fallback::ondemand::array_iterator>::operator==(const simdjson_result<fallback::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<fallback::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<fallback::ondemand::array_iterator>::operator!=(const simdjson_result<fallback::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> &simdjson_result<fallback::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for fallback */
 /* including simdjson/generic/ondemand/document-inl.h for fallback: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for fallback */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -47040,10 +48952,12 @@ simdjson_inline simdjson_result<fallback::ondemand::array_iterator> &simdjson_re
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -47197,6 +49111,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -47205,13 +49129,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -47273,7 +49190,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -47295,6 +49219,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -47850,6 +49776,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::docume
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -47862,6 +49808,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::docume
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -47879,10 +49837,12 @@ simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fall
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, fallback::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, fallback::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -48104,7 +50064,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -49626,497 +51585,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
-  fallback::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for fallback */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for fallback: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace fallback {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace fallback
@@ -50124,343 +51652,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(fallback::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(std::forward<fallback::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
+  fallback::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape_wobbly(fallback::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
-/* including simdjson/generic/ondemand/serialization-inl.h for fallback: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace fallback {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace fallback::ondemand;
-  fallback::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      fallback::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      fallback::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace fallback { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::fallback::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::fallback::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for fallback */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
-}
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -50469,560 +51889,554 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(fallback::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(std::forward<fallback::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/value-inl.h for fallback: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for fallback */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for fallback: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
   }
+  return true;
 }
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(fallback::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(std::forward<fallback::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(error) {}
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape_wobbly(fallback::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
+/* including simdjson/generic/ondemand/serialization-inl.h for fallback: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
+
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace fallback::ondemand;
+  fallback::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
   switch (t)
   {
     case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
+    {
+      fallback::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
     case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
+    {
+      fallback::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
     default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+      return trim(x.raw_json_token());
   }
 }
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
-  fallback::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::value>(
-      std::forward<fallback::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+namespace simdjson { namespace fallback { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::fallback::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::fallback::ondemand
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for fallback */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
-template<> simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>(fallback::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<fallback::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(fallback::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(std::forward<fallback::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for fallback */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -51826,6 +53240,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -52117,6 +53533,8 @@ simdjson_inline simdjson_result<fallback::ondemand::value_iterator>::simdjson_re
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for fallback */
 /* including simdjson/fallback/end.h: #include "simdjson/fallback/end.h" */
 /* begin file simdjson/fallback/end.h */
@@ -52228,8 +53646,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
 /* end file simdjson/haswell/intrinsics.h */
 
 #if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+// We enable bmi2 only if LLVM/clang is used, because GCC may not
+// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
+#if defined(__clang__)
+SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
+#else
 SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
 #endif
+#endif
 
 /* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
 /* begin file simdjson/haswell/bitmanipulation.h */
@@ -52886,6 +54310,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for haswell */
+/* including simdjson/generic/ondemand/deserialize.h for haswell: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for haswell */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = haswell::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = haswell::ondemand::value;
+  using document_type = haswell::ondemand::document;
+  using document_reference_type = haswell::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for haswell */
 /* including simdjson/generic/ondemand/value_iterator.h for haswell: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for haswell */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -53390,12 +54940,15 @@ struct simdjson_result<haswell::ondemand::value_iterator> : public haswell::impl
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace haswell {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -53420,16 +54973,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -53439,7 +54997,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -53515,6 +55098,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -53766,6 +55360,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -54133,6 +55728,7 @@ struct simdjson_result<haswell::ondemand::value> : public haswell::implementatio
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -55188,6 +56784,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -55382,8 +56994,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -55525,7 +57141,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -55803,8 +57420,11 @@ struct simdjson_result<haswell::ondemand::array_iterator> : public haswell::impl
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
@@ -55977,24 +57597,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -56008,7 +57643,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -56110,7 +57770,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -56222,6 +57883,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -56490,6 +58152,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -56515,7 +58182,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -56540,6 +58270,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -56618,6 +58349,7 @@ struct simdjson_result<haswell::ondemand::document> : public haswell::implementa
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::json_type> type() noexcept;
@@ -56667,8 +58399,14 @@ struct simdjson_result<haswell::ondemand::document_reference> : public haswell::
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator haswell::ondemand::array() & noexcept(false);
   simdjson_inline operator haswell::ondemand::object() & noexcept(false);
@@ -56689,6 +58427,7 @@ struct simdjson_result<haswell::ondemand::document_reference> : public haswell::
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::json_type> type() noexcept;
@@ -57619,6 +59358,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for haswell */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for haswell: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for haswell */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  haswell::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for haswell */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for haswell: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for haswell */
@@ -57626,6 +59536,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -57738,115 +59649,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::array>::simdjson_result(
+  haswell::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::array>(
+      std::forward<haswell::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<haswell::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<haswell::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for haswell */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator>::simdjson_result(
+  haswell::ondemand::array_iterator &&value
+) noexcept
+  : haswell::implementation_simdjson_result_base<haswell::ondemand::array_iterator>(std::forward<haswell::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : haswell::implementation_simdjson_result_base<haswell::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<haswell::ondemand::array_iterator>::operator==(const simdjson_result<haswell::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<haswell::ondemand::array_iterator>::operator!=(const simdjson_result<haswell::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> &simdjson_result<haswell::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -57855,138 +60157,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::array>::simdjson_result(
-  haswell::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::array>(
-      std::forward<haswell::ondemand::array>(value)
+simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
+  haswell::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::value>(
+      std::forward<haswell::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<haswell::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<haswell::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for haswell */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator>::simdjson_result(
-  haswell::ondemand::array_iterator &&value
-) noexcept
-  : haswell::implementation_simdjson_result_base<haswell::ondemand::array_iterator>(std::forward<haswell::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : haswell::implementation_simdjson_result_base<haswell::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<haswell::ondemand::array_iterator>::operator==(const simdjson_result<haswell::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<haswell::ondemand::array_iterator>::operator!=(const simdjson_result<haswell::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> &simdjson_result<haswell::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for haswell */
 /* including simdjson/generic/ondemand/document-inl.h for haswell: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for haswell */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -57999,10 +60417,12 @@ simdjson_inline simdjson_result<haswell::ondemand::array_iterator> &simdjson_res
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -58156,6 +60576,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -58164,13 +60594,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -58232,7 +60655,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -58254,6 +60684,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -58809,6 +61241,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::documen
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -58821,6 +61273,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::documen
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -58838,10 +61302,12 @@ simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswe
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, haswell::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, haswell::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -59063,7 +61529,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -60585,497 +63050,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
-  haswell::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for haswell */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for haswell: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace haswell {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace haswell
@@ -61083,343 +63117,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(haswell::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(std::forward<haswell::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
+  haswell::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape_wobbly(haswell::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
-/* including simdjson/generic/ondemand/serialization-inl.h for haswell: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace haswell {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace haswell::ondemand;
-  haswell::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      haswell::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      haswell::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace haswell { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::haswell::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::haswell::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for haswell */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -61428,304 +63354,191 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(haswell::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(std::forward<haswell::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for haswell */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for haswell: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
   }
 }
 
@@ -61735,253 +63548,360 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
-  haswell::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::value>(
-      std::forward<haswell::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_elements() & noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(haswell::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(std::forward<haswell::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.raw();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
   if (error()) { return error(); }
-  return first.count_fields();
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape_wobbly(haswell::ondemand::json_iterator &iter) const noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.unescape_wobbly(iter);
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
+/* including simdjson/generic/ondemand/serialization-inl.h for haswell: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+
+
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
+}
+
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
+}
+
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace haswell::ondemand;
+  haswell::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      haswell::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      haswell::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+} // namespace simdjson
+
+namespace simdjson { namespace haswell { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::haswell::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::haswell::ondemand
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for haswell */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(haswell::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(std::forward<haswell::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for haswell */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -62785,6 +64705,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -63076,6 +64998,8 @@ simdjson_inline simdjson_result<haswell::ondemand::value_iterator>::simdjson_res
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for haswell */
 /* including simdjson/haswell/end.h: #include "simdjson/haswell/end.h" */
 /* begin file simdjson/haswell/end.h */
@@ -63844,6 +65768,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for icelake */
+/* including simdjson/generic/ondemand/deserialize.h for icelake: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for icelake */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = icelake::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = icelake::ondemand::value;
+  using document_type = icelake::ondemand::document;
+  using document_reference_type = icelake::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for icelake */
 /* including simdjson/generic/ondemand/value_iterator.h for icelake: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for icelake */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -64348,12 +66398,15 @@ struct simdjson_result<icelake::ondemand::value_iterator> : public icelake::impl
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace icelake {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -64378,16 +66431,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -64397,7 +66455,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -64473,6 +66556,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -64724,6 +66818,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -65091,6 +67186,7 @@ struct simdjson_result<icelake::ondemand::value> : public icelake::implementatio
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -66146,6 +68242,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -66340,8 +68452,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -66483,7 +68599,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -66761,8 +68878,11 @@ struct simdjson_result<icelake::ondemand::array_iterator> : public icelake::impl
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
@@ -66935,24 +69055,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -66966,7 +69101,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -67068,7 +69228,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -67180,6 +69341,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -67448,6 +69610,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -67473,7 +69640,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -67498,6 +69728,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -67576,6 +69807,7 @@ struct simdjson_result<icelake::ondemand::document> : public icelake::implementa
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
@@ -67625,8 +69857,14 @@ struct simdjson_result<icelake::ondemand::document_reference> : public icelake::
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator icelake::ondemand::array() & noexcept(false);
   simdjson_inline operator icelake::ondemand::object() & noexcept(false);
@@ -67647,6 +69885,7 @@ struct simdjson_result<icelake::ondemand::document_reference> : public icelake::
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
@@ -68577,6 +70816,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for icelake */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for icelake: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for icelake */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  icelake::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for icelake */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for icelake: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for icelake */
@@ -68584,6 +70994,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -68696,115 +71107,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+  icelake::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::array>(
+      std::forward<icelake::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<icelake::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for icelake */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(
+  icelake::ondemand::array_iterator &&value
+) noexcept
+  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>(std::forward<icelake::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator==(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator!=(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &simdjson_result<icelake::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -68813,138 +71615,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
-  icelake::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::array>(
-      std::forward<icelake::ondemand::array>(value)
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  icelake::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(
+      std::forward<icelake::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<icelake::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for icelake */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(
-  icelake::ondemand::array_iterator &&value
-) noexcept
-  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>(std::forward<icelake::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator==(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator!=(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &simdjson_result<icelake::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for icelake */
 /* including simdjson/generic/ondemand/document-inl.h for icelake: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for icelake */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -68957,10 +71875,12 @@ simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &simdjson_res
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -69114,6 +72034,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -69122,13 +72052,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -69190,7 +72113,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -69212,6 +72142,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -69767,6 +72699,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::documen
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<icelake::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<icelake::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -69779,6 +72731,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::documen
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -69796,10 +72760,12 @@ simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icela
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, icelake::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, icelake::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -70021,7 +72987,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -71543,497 +74508,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
-  icelake::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for icelake */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for icelake: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace icelake
@@ -72041,343 +74575,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(std::forward<icelake::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
+  icelake::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
-/* including simdjson/generic/ondemand/serialization-inl.h for icelake: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace icelake::ondemand;
-  icelake::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      icelake::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      icelake::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace icelake { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::icelake::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::icelake::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for icelake */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
-}
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -72386,560 +74812,554 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(icelake::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(std::forward<icelake::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for icelake */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for icelake: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace icelake {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
   }
+  return true;
 }
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(std::forward<icelake::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(error) {}
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
+/* including simdjson/generic/ondemand/serialization-inl.h for icelake: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
+
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace icelake::ondemand;
+  icelake::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
   switch (t)
   {
     case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
+    {
+      icelake::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
     case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
+    {
+      icelake::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
     default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+      return trim(x.raw_json_token());
   }
 }
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  icelake::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(
-      std::forward<icelake::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+namespace simdjson { namespace icelake { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::icelake::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::icelake::ondemand
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for icelake */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
-template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(icelake::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(std::forward<icelake::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for icelake */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -73743,6 +76163,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -74034,6 +76456,8 @@ simdjson_inline simdjson_result<icelake::ondemand::value_iterator>::simdjson_res
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for icelake */
 /* including simdjson/icelake/end.h: #include "simdjson/icelake/end.h" */
 /* begin file simdjson/icelake/end.h */
@@ -74310,7 +76734,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace ppc64
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
 /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -74917,6 +77347,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for ppc64 */
+/* including simdjson/generic/ondemand/deserialize.h for ppc64: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for ppc64 */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = ppc64::ondemand::value;
+  using document_type = ppc64::ondemand::document;
+  using document_reference_type = ppc64::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for ppc64 */
 /* including simdjson/generic/ondemand/value_iterator.h for ppc64: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for ppc64 */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -75421,12 +77977,15 @@ struct simdjson_result<ppc64::ondemand::value_iterator> : public ppc64::implemen
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace ppc64 {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -75451,16 +78010,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -75470,7 +78034,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -75546,6 +78135,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -75797,6 +78397,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -76164,6 +78765,7 @@ struct simdjson_result<ppc64::ondemand::value> : public ppc64::implementation_si
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<ppc64::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -77219,6 +79821,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -77413,8 +80031,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -77556,7 +80178,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -77834,8 +80457,11 @@ struct simdjson_result<ppc64::ondemand::array_iterator> : public ppc64::implemen
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
@@ -78008,24 +80634,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -78039,7 +80680,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -78141,7 +80807,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -78253,6 +80920,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -78521,6 +81189,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -78546,7 +81219,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -78571,6 +81307,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -78649,6 +81386,7 @@ struct simdjson_result<ppc64::ondemand::document> : public ppc64::implementation
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<ppc64::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::json_type> type() noexcept;
@@ -78698,8 +81436,14 @@ struct simdjson_result<ppc64::ondemand::document_reference> : public ppc64::impl
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator ppc64::ondemand::array() & noexcept(false);
   simdjson_inline operator ppc64::ondemand::object() & noexcept(false);
@@ -78720,6 +81464,7 @@ struct simdjson_result<ppc64::ondemand::document_reference> : public ppc64::impl
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<ppc64::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<ppc64::ondemand::json_type> type() noexcept;
@@ -79650,6 +82395,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for ppc64 */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for ppc64: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for ppc64 */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  ppc64::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for ppc64 */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for ppc64: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for ppc64 */
@@ -79657,6 +82573,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -79769,115 +82686,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::array>::simdjson_result(
+  ppc64::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::array>(
+      std::forward<ppc64::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<ppc64::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator>::simdjson_result(
+  ppc64::ondemand::array_iterator &&value
+) noexcept
+  : ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator>(std::forward<ppc64::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<ppc64::ondemand::array_iterator>::operator==(const simdjson_result<ppc64::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<ppc64::ondemand::array_iterator>::operator!=(const simdjson_result<ppc64::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> &simdjson_result<ppc64::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/value-inl.h for ppc64: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -79886,138 +83194,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::array>::simdjson_result(
-  ppc64::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::array>(
-      std::forward<ppc64::ondemand::array>(value)
+simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
+  ppc64::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::value>(
+      std::forward<ppc64::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<ppc64::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator>::simdjson_result(
-  ppc64::ondemand::array_iterator &&value
-) noexcept
-  : ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator>(std::forward<ppc64::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<ppc64::ondemand::array_iterator>::operator==(const simdjson_result<ppc64::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<ppc64::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<ppc64::ondemand::array_iterator>::operator!=(const simdjson_result<ppc64::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> &simdjson_result<ppc64::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for ppc64 */
 /* including simdjson/generic/ondemand/document-inl.h for ppc64: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for ppc64 */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -80030,10 +83454,12 @@ simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> &simdjson_resul
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -80187,6 +83613,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -80195,13 +83631,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -80263,7 +83692,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -80285,6 +83721,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -80840,6 +84278,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -80852,6 +84310,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -80869,10 +84339,12 @@ simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, ppc64::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, ppc64::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -81094,7 +84566,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -82616,497 +86087,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
-  ppc64::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace ppc64
@@ -83114,343 +86154,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(std::forward<ppc64::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
+  ppc64::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/serialization-inl.h for ppc64: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace ppc64::ondemand;
-  ppc64::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      ppc64::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      ppc64::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace ppc64 { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::ppc64::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::ppc64::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -83459,304 +86391,191 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(std::forward<ppc64::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/value-inl.h for ppc64: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
   }
 }
 
@@ -83766,253 +86585,360 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
-  ppc64::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::value>(
-      std::forward<ppc64::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_elements() & noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(std::forward<ppc64::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.raw();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
   if (error()) { return error(); }
-  return first.count_fields();
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.unescape_wobbly(iter);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/serialization-inl.h for ppc64: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+
+
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
+}
+
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
+}
+
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace ppc64::ondemand;
+  ppc64::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      ppc64::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      ppc64::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+} // namespace simdjson
+
+namespace simdjson { namespace ppc64 { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-template<> simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::ppc64::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::ppc64::ondemand
 
-simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<ppc64::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(std::forward<ppc64::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for ppc64 */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -84816,6 +87742,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -85107,6 +88035,8 @@ simdjson_inline simdjson_result<ppc64::ondemand::value_iterator>::simdjson_resul
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for ppc64 */
 /* including simdjson/ppc64/end.h: #include "simdjson/ppc64/end.h" */
 /* begin file simdjson/ppc64/end.h */
@@ -86313,6 +89243,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for westmere */
+/* including simdjson/generic/ondemand/deserialize.h for westmere: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for westmere */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = westmere::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = westmere::ondemand::value;
+  using document_type = westmere::ondemand::document;
+  using document_reference_type = westmere::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for westmere */
 /* including simdjson/generic/ondemand/value_iterator.h for westmere: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for westmere */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -86817,12 +89873,15 @@ struct simdjson_result<westmere::ondemand::value_iterator> : public westmere::im
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace westmere {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -86847,16 +89906,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -86866,7 +89930,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -86942,6 +90031,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -87193,6 +90293,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -87560,6 +90661,7 @@ struct simdjson_result<westmere::ondemand::value> : public westmere::implementat
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -88615,6 +91717,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -88809,8 +91927,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -88952,7 +92074,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -89230,8 +92353,11 @@ struct simdjson_result<westmere::ondemand::array_iterator> : public westmere::im
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
@@ -89404,24 +92530,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -89435,7 +92576,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -89537,7 +92703,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -89649,6 +92816,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -89917,6 +93085,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -89942,7 +93115,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -89967,6 +93203,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -90045,6 +93282,7 @@ struct simdjson_result<westmere::ondemand::document> : public westmere::implemen
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
@@ -90094,8 +93332,14 @@ struct simdjson_result<westmere::ondemand::document_reference> : public westmere
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator westmere::ondemand::array() & noexcept(false);
   simdjson_inline operator westmere::ondemand::object() & noexcept(false);
@@ -90116,6 +93360,7 @@ struct simdjson_result<westmere::ondemand::document_reference> : public westmere
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
@@ -91046,6 +94291,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for westmere */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for westmere: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for westmere */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  westmere::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for westmere */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for westmere: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for westmere */
@@ -91053,6 +94469,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -91165,115 +94582,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+  westmere::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::array>(
+      std::forward<westmere::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<westmere::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for westmere */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(
+  westmere::ondemand::array_iterator &&value
+) noexcept
+  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>(std::forward<westmere::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator==(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator!=(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &simdjson_result<westmere::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -91282,138 +95090,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
-  westmere::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::array>(
-      std::forward<westmere::ondemand::array>(value)
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
+  westmere::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(
+      std::forward<westmere::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<westmere::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for westmere */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(
-  westmere::ondemand::array_iterator &&value
-) noexcept
-  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>(std::forward<westmere::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator==(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator!=(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &simdjson_result<westmere::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for westmere */
 /* including simdjson/generic/ondemand/document-inl.h for westmere: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for westmere */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -91426,10 +95350,12 @@ simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &simdjson_re
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -91583,6 +95509,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -91591,13 +95527,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -91659,7 +95588,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -91681,6 +95617,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -92236,6 +96174,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::docume
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -92248,6 +96206,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::docume
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -92265,10 +96235,12 @@ simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<west
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, westmere::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, westmere::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -92490,7 +96462,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -94012,497 +97983,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
-  westmere::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for westmere */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for westmere: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace westmere {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace westmere
@@ -94510,343 +98050,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(std::forward<westmere::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
+  westmere::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
-/* including simdjson/generic/ondemand/serialization-inl.h for westmere: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace westmere::ondemand;
-  westmere::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      westmere::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      westmere::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace westmere { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::westmere::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::westmere::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for westmere */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
-}
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -94855,560 +98287,554 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(westmere::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(std::forward<westmere::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for westmere */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for westmere: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
   }
+  return true;
 }
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(std::forward<westmere::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(error) {}
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
+/* including simdjson/generic/ondemand/serialization-inl.h for westmere: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
+
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace westmere::ondemand;
+  westmere::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
   switch (t)
   {
     case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
+    {
+      westmere::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
     case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
+    {
+      westmere::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
     default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+      return trim(x.raw_json_token());
   }
 }
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
-  westmere::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(
-      std::forward<westmere::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+namespace simdjson { namespace westmere { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::westmere::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::westmere::ondemand
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for westmere */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
-template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(westmere::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(std::forward<westmere::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for westmere */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -96212,6 +99638,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -96503,6 +99931,8 @@ simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_re
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for westmere */
 /* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */
 /* begin file simdjson/westmere/end.h */
@@ -96703,7 +100133,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lsx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lsx/numberparsing_defs.h */
@@ -97180,6 +100616,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for lsx */
+/* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for lsx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = lsx::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = lsx::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = lsx::ondemand::value;
+  using document_type = lsx::ondemand::document;
+  using document_reference_type = lsx::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for lsx */
 /* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for lsx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -97684,12 +101246,15 @@ struct simdjson_result<lsx::ondemand::value_iterator> : public lsx::implementati
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace lsx {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -97714,16 +101279,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -97733,7 +101303,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -97809,6 +101404,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -98060,6 +101666,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -98427,6 +102034,7 @@ struct simdjson_result<lsx::ondemand::value> : public lsx::implementation_simdjs
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -99482,6 +103090,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -99676,8 +103300,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -99819,7 +103447,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -100097,8 +103726,11 @@ struct simdjson_result<lsx::ondemand::array_iterator> : public lsx::implementati
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
@@ -100271,24 +103903,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -100302,7 +103949,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -100404,7 +104076,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -100516,6 +104189,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -100784,6 +104458,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -100809,7 +104488,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -100834,6 +104576,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -100912,6 +104655,7 @@ struct simdjson_result<lsx::ondemand::document> : public lsx::implementation_sim
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
@@ -100961,8 +104705,14 @@ struct simdjson_result<lsx::ondemand::document_reference> : public lsx::implemen
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator lsx::ondemand::array() & noexcept(false);
   simdjson_inline operator lsx::ondemand::object() & noexcept(false);
@@ -100983,6 +104733,7 @@ struct simdjson_result<lsx::ondemand::document_reference> : public lsx::implemen
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
@@ -101913,6 +105664,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for lsx */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for lsx: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for lsx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  lsx::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for lsx */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for lsx: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for lsx */
@@ -101920,6 +105842,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -102032,115 +105955,506 @@ simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
   iter.reset_array();
   return count;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
+  lsx::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::array>(
+      std::forward<lsx::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<lsx::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for lsx */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(
+  lsx::ondemand::array_iterator &&value
+) noexcept
+  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>(std::forward<lsx::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator==(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator!=(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &simdjson_result<lsx::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -102149,138 +106463,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
-  lsx::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::array>(
-      std::forward<lsx::ondemand::array>(value)
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+  lsx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(
+      std::forward<lsx::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<lsx::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for lsx */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(
-  lsx::ondemand::array_iterator &&value
-) noexcept
-  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>(std::forward<lsx::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator==(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator!=(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &simdjson_result<lsx::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for lsx */
 /* including simdjson/generic/ondemand/document-inl.h for lsx: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for lsx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -102293,10 +106723,12 @@ simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &simdjson_result<
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -102450,6 +106882,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -102458,13 +106900,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -102526,7 +106961,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -102548,6 +106990,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -103103,6 +107547,26 @@ simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_re
   if (error()) { return error(); }
   return first.is_null();
 }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>(out);
+}
 simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
@@ -103115,6 +107579,18 @@ simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_re
   if (error()) { return error(); }
   return first.is_string();
 }
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
@@ -103132,10 +107608,12 @@ simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::onde
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document_reference>::value == false>::type>
+template <class T>
 simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, lsx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, lsx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -103357,7 +107835,6 @@ simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bo
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
@@ -104879,497 +109356,66 @@ simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
 simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
   return !(*this != other);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
-  lsx::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for lsx */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for lsx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace lsx
@@ -105377,343 +109423,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(std::forward<lsx::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
+  lsx::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
-/* including simdjson/generic/ondemand/serialization-inl.h for lsx: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace lsx::ondemand;
-  lsx::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      lsx::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      lsx::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace lsx { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lsx::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::lsx::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for lsx */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
-}
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -105722,560 +109660,554 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(lsx::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(std::forward<lsx::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for lsx */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for lsx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace lsx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
   }
+  return true;
 }
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(std::forward<lsx::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(error) {}
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
+/* including simdjson/generic/ondemand/serialization-inl.h for lsx: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
+
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace lsx::ondemand;
+  lsx::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
   switch (t)
   {
     case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
+    {
+      lsx::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
     case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
+    {
+      lsx::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
     default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+      return trim(x.raw_json_token());
   }
 }
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
-  lsx::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(
-      std::forward<lsx::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+namespace simdjson { namespace lsx { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lsx::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::lsx::ondemand
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for lsx */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
-template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(lsx::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(std::forward<lsx::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for lsx */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -107079,6 +111011,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -107370,6 +111304,8 @@ simdjson_inline simdjson_result<lsx::ondemand::value_iterator>::simdjson_result(
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for lsx */
 /* including simdjson/lsx/end.h: #include "simdjson/lsx/end.h" */
 /* begin file simdjson/lsx/end.h */
@@ -107567,7 +111503,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
 } // namespace lasx
 } // namespace simdjson
 
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
 #define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
 #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
 /* end file simdjson/lasx/numberparsing_defs.h */
@@ -108060,6 +112002,132 @@ class value_iterator;
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
 /* end file simdjson/generic/ondemand/base.h for lasx */
+/* including simdjson/generic/ondemand/deserialize.h for lasx: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for lasx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = lasx::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = lasx::ondemand::value;
+  using document_type = lasx::ondemand::document;
+  using document_reference_type = lasx::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for lasx */
 /* including simdjson/generic/ondemand/value_iterator.h for lasx: #include "simdjson/generic/ondemand/value_iterator.h" */
 /* begin file simdjson/generic/ondemand/value_iterator.h for lasx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
@@ -108564,12 +112632,15 @@ struct simdjson_result<lasx::ondemand::value_iterator> : public lasx::implementa
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace lasx {
 namespace ondemand {
-
 /**
  * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
  * not access more data in the JSON document.
@@ -108594,16 +112665,21 @@ class value {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
   }
 
+
   /**
    * Get this value as the given type.
    *
@@ -108613,7 +112689,32 @@ class value {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Cast this JSON value to an array.
@@ -108689,6 +112790,17 @@ class value {
    * Important: a value should be consumed once. Calling get_string() twice on the same value
    * is an error.
    *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
    * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
    *          time it parses a document or when it is destroyed.
    * @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -108940,6 +113052,7 @@ class value {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -109307,6 +113420,7 @@ struct simdjson_result<lasx::ondemand::value> : public lasx::implementation_simd
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) noexcept;
   /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) noexcept = delete;
 
   /**
    * Get the type of this JSON value.
@@ -110362,6 +114476,22 @@ class parser {
    * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
    * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
    * @param json The JSON to parse.
    * @param len The length of the JSON.
    * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -110556,8 +114686,12 @@ class parser {
    * behavior of the parser for future operations.
    */
   bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
   #endif
-
   /**
    * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
    * The result must be valid UTF-8.
@@ -110699,7 +114833,8 @@ class array {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
    * To check that an array is empty, it is more performant to use
    * the is_empty() method.
@@ -110977,8 +115112,11 @@ struct simdjson_result<lasx::ondemand::array_iterator> : public lasx::implementa
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
@@ -111151,24 +115289,39 @@ class document {
    * @returns A value of the given type, parsed from the JSON.
    * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
-  }
-  /** @overload template<typename T> simdjson_result<T> get() & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
-    // Unless the simdjson library or the user provides an inline implementation, calling this method should
-    // immediately fail.
-    static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-      "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-      "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-      " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-      " You may also add support for custom types, see our documentation.");
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
   }
 
   /**
@@ -111182,7 +115335,32 @@ class document {
    * @returns INCORRECT_TYPE If the JSON value is not an object.
    * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
   template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
@@ -111284,7 +115462,8 @@ class document {
    * calling this function, if successful, the array is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
    /**
@@ -111396,6 +115575,7 @@ class document {
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
    * Get the type of this JSON value. It does not validate or consume the value.
@@ -111664,6 +115844,11 @@ class document {
 
 /**
  * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
 class document_reference {
 public:
@@ -111689,7 +115874,70 @@ class document_reference {
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
   simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
@@ -111714,6 +115962,7 @@ class document_reference {
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
@@ -111792,6 +116041,7 @@ struct simdjson_result<lasx::ondemand::document> : public lasx::implementation_s
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
@@ -111841,8 +116091,14 @@ struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implem
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document_reference>::value == false>::type>
+  template <class T>
   explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator lasx::ondemand::array() & noexcept(false);
   simdjson_inline operator lasx::ondemand::object() & noexcept(false);
@@ -111863,6 +116119,7 @@ struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implem
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
   simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
@@ -112793,6 +117050,177 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 #endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 /* end file simdjson/generic/ondemand/serialization.h for lasx */
 
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for lasx: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for lasx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  lasx::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for lasx */
+
 // Inline definitions
 /* including simdjson/generic/ondemand/array-inl.h for lasx: #include "simdjson/generic/ondemand/array-inl.h" */
 /* begin file simdjson/generic/ondemand/array-inl.h for lasx */
@@ -112800,6 +117228,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
@@ -112850,177 +117279,568 @@ namespace ondemand {
 //   error == SUCCESS.
 //
 
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  bool has_value;
+  SIMDJSON_TRY(iter.started_array().get(has_value));
+  return array(iter);
+}
+
+simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return array_iterator(iter);
+}
+simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
+  return array_iterator(iter);
+}
+simdjson_inline error_code array::consume() noexcept {
+  auto error = iter.json_iter().skip_child(iter.depth()-1);
+  if(error) { iter.abandon(); }
+  return error;
+}
+
+simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
+
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the array after counting the number of elements.
+  iter.reset_array();
+  return count;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
+
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+  lasx::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(
+      std::forward<lasx::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for lasx */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
+  lasx::ondemand::array_iterator &&value
+) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
 }
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
 
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
 }
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
 }
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
-  bool has_value;
-  SIMDJSON_TRY(iter.started_array().get(has_value));
-  return array(iter);
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
 }
 
-simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return array_iterator(iter);
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
-  return array_iterator(iter);
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
 }
-simdjson_inline error_code array::consume() noexcept {
-  auto error = iter.json_iter().skip_child(iter.depth()-1);
-  if(error) { iter.abandon(); }
-  return error;
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
 }
 
-simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the array after counting the number of elements.
-  iter.reset_array();
-  return count;
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
   if(error) { return error; }
-  return !is_not_empty;
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
-
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
 }
 
-inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
-  if (json_path.empty() || (json_path.front() != '.' &&
-      json_path.front() != '[')) {
-    return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
   }
+}
 
-  std::string result;
-  // Reserve space to reduce allocations, adjusting for potential increases due
-  // to escaping.
-  result.reserve(json_path.size() * 2);
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  size_t i = 0;
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  while (i < json_path.length()) {
-    if (json_path[i] == '.') {
-      result += '/';
-    } else if (json_path[i] == '[') {
-      result += '/';
-      ++i; // Move past the '['
-      while (i < json_path.length() && json_path[i] != ']') {
-          if (json_path[i] == '~') {
-            result += "~0";
-          } else if (json_path[i] == '/') {
-            result += "~1";
-          } else {
-            result += json_path[i];
-          }
-          ++i;
-      }
-      if (i == json_path.length() || json_path[i] != ']') {
-          return "-1"; // Using sentinel value that will be handled as an error by the caller.
-      }
-    } else {
-      if (json_path[i] == '~') {
-          result += "~0";
-      } else if (json_path[i] == '/') {
-          result += "~1";
-      } else {
-          result += json_path[i];
-      }
-    }
-    ++i;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
   }
-
-  return result;
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -113029,138 +117849,254 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
-  lasx::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(
-      std::forward<lasx::ondemand::array>(value)
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+  lasx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(
+      std::forward<lasx::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for lasx */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
-  lasx::ondemand::array_iterator &&value
-) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
-{
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.current_location();
 }
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for lasx */
 /* including simdjson/generic/ondemand/document-inl.h for lasx: #include "simdjson/generic/ondemand/document-inl.h" */
 /* begin file simdjson/generic/ondemand/document-inl.h for lasx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
@@ -113173,10 +118109,12 @@ simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -113330,6 +118268,16 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
 template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
 template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
 template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
@@ -113338,13 +118286,6 @@ template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document
 template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
 template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
-  return get<T>().get(out);
-}
-template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
-  return std::forward<document>(*this).get<T>().get(out);
-}
-
 #if SIMDJSON_EXCEPTIONS
 template <class T>
 simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
@@ -113406,7 +118347,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
 }
 
 simdjson_inline error_code document::consume() noexcept {
-  auto error = iter.skip_child(0);
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
@@ -113428,6 +118376,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
 }
 
 simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
@@ -113474,1732 +118424,1056 @@ simdjson_inline simdjson_result<value> document::at_pointer(std::string_view jso
   {
     case json_type::array:
       return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::document>::simdjson_result(
-  lasx::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document>(
-      std::forward<lasx::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document>(
-      error
-    )
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first).get<T>();
-}
-template<typename T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-template<typename T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first).get<T>(out);
-}
-
-template<> simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<lasx::ondemand::document>(first);
-  return SUCCESS;
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-
-simdjson_inline bool simdjson_result<lasx::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-
-
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-#endif
-
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline bool simdjson_result<lasx::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
-}
-
-
-simdjson_inline int32_t simdjson_result<lasx::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
-
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
-
-
 namespace simdjson {
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::simdjson_result(lasx::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<lasx::ondemand::document_reference>(std::forward<lasx::ondemand::document_reference>(value), error) {}
-
 
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_elements() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::document>::simdjson_result(
+  lasx::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document>(
+      std::forward<lasx::ondemand::document>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document>(
+      error
+    )
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::rewind() noexcept {
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::rewind() noexcept {
   if (error()) { return error(); }
   first.rewind();
   return SUCCESS;
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::begin() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::end() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document>::end() & noexcept {
   return {};
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document_reference>::get_array() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document_reference>::get_object() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document_reference>::value == false>::type>
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-#endif
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for lasx */
-/* including simdjson/generic/ondemand/document_stream-inl.h for lasx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <algorithm>
-#include <stdexcept>
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
-
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
-
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
-
-
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
-}
-
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
-}
-
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
-}
-
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
-}
-
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
-}
-
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
-}
-
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
-}
-
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
-}
-
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
-}
-
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  //if(stream->error) { return stream->error; }
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
-}
-
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
-}
-
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
-
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
-}
-
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
-}
-
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
-}
-
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
+  return first.get_double();
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first).get<T>(out);
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
+template<> simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<lasx::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
 
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
+simdjson_inline bool simdjson_result<lasx::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
 
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
 
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
 
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline bool simdjson_result<lasx::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
+}
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
 
-namespace simdjson {
+simdjson_inline int32_t simdjson_result<lasx::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
 
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
-{
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  lasx::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
-      std::forward<lasx::ondemand::document_stream>(value)
-    )
-{
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
 }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
-/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+} // namespace simdjson
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
-}
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
-}
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
-}
+namespace simdjson {
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::simdjson_result(lasx::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<lasx::ondemand::document_reference>(std::forward<lasx::ondemand::document_reference>(value), error) {}
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
+
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
   return SUCCESS;
 }
-
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+template <class T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document_reference>(first).get<T>(out);
 }
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  lasx::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(
-      std::forward<lasx::ondemand::field>(value)
-    )
-{
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(error)
-{
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_string() noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.is_string();
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+template <>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) & noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  out = first;
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+template <>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) && noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  out = first;
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.is_negative();
 }
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_integer() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.is_integer();
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document_reference>::get_number_type() noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.get_number_type();
 }
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, lasx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, lasx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_path(json_path);
 }
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
-}
+} // namespace simdjson
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for lasx */
+/* including simdjson/generic/ondemand/document_stream-inl.h for lasx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
+#include <algorithm>
+#include <stdexcept>
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
-}
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
-}
+#endif  // SIMDJSON_THREADS_ENABLED
 
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
 }
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
 
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
   }
-  return true;
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
     }
-    return out;
+  }
 }
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
-#endif
 
-
-
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
-}
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
-}
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
-}
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
-}
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
-  return double(payload.unsigned_integer);
 }
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
-}
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
-}
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
-}
+#endif // SIMDJSON_THREADS_ENABLED
 
 } // namespace ondemand
 } // namespace lasx
@@ -115207,618 +119481,588 @@ simdjson_inline void number::skip_double() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  lasx::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
+      std::forward<lasx::ondemand::document_stream>(value)
+    )
+{
+}
 
-} // namespace simdjson
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
-/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
+/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
-}
-
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
-}
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-static inline log_level get_log_level_from_env()
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
 {
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
-}
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  lasx::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(
+      std::forward<lasx::ondemand::field>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(error)
+{
 }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+  if (error()) { return error(); }
+  return first.key();
 }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+  if (error()) { return error(); }
+  return first.escaped_key();
+}
 
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(allow_replacement);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+template<typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
-/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
 }
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
+
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
+}
+
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
   }
-  return value(iter.child());
+  return count == 0;
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
   }
-  return value(iter.child());
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
 #endif
-  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
+}
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
+}
 
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
   }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
   }
-  return child;
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
+}
 
-namespace simdjson {
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
+}
 
-simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(lasx::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::object>(std::forward<lasx::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::object>(error) {}
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
+}
 
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first).find_field_unordered(key);
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first)[key];
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first).find_field(key);
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
 
-inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
 
-inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for lasx */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+#if SIMDJSON_DEVELOPMENT_CHECKS
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+}
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+}
 
-//
-// object_iterator
-//
+#endif
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
 
 } // namespace ondemand
 } // namespace lasx
@@ -115826,774 +120070,974 @@ SIMDJSON_POP_DISABLE_WARNINGS
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(
-  lasx::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>(std::forward<lasx::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::field> simdjson_result<lasx::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator==(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator!=(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &simdjson_result<lasx::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/parser-inl.h for lasx: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
+}
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
+
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
+}
 
-  json.remove_utf8_bom();
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
+}
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
+}
+
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
+}
+
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
+}
+
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
+}
+
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
+}
+
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
+}
+
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
   }
+  return double(payload.unsigned_integer);
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
+}
+
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
+}
+
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
+}
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
+/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  json.remove_utf8_bom();
+#include <memory>
+#include <cstring>
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+namespace logger {
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
+
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
   }
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
+} // namespace logger
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(lasx::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::parser>(std::forward<lasx::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for lasx */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for lasx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
+/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  return true;
+  return value(iter.child());
 }
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  return true;
+  return value(iter.child());
 }
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return value(iter.child());
 }
 
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
+}
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
+}
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
+}
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
 
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(lasx::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::object>(std::forward<lasx::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::object>(first).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::object>(first)[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::object>(first).find_field(key);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
   }
+  return first.at_path(json_path);
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string>::simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::raw_json_string>(std::forward<lasx::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::raw_json_string>(error) {}
+inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::reset() noexcept {
+  if (error()) { return error(); }
+  return first.reset();
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::raw_json_string>::raw() const noexcept {
+inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return first.is_empty();
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lasx::ondemand::raw_json_string>::unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+
+simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+  return first.count_fields();
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lasx::ondemand::raw_json_string>::unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept {
+
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::object>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+  return first.raw_json();
 }
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
-/* including simdjson/generic/ondemand/serialization-inl.h for lasx: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for lasx */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+//
+// object_iterator
+//
 
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace lasx::ondemand;
-  lasx::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      lasx::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      lasx::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
-  }
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
 }
-
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-namespace simdjson { namespace lasx { namespace ondemand {
+namespace simdjson {
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(
+  lasx::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>(std::forward<lasx::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>({}, error)
+{
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
+simdjson_inline simdjson_result<lasx::ondemand::field> simdjson_result<lasx::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator==(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator!=(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &simdjson_result<lasx::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/parser-inl.h for lasx: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
+
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
   } else {
-    throw simdjson::simdjson_error(error);
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
 #endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lasx::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
-#endif
-}}} // namespace simdjson::lasx::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for lasx */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  json.remove_utf8_bom();
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
 
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
 
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
 }
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
+
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -116602,304 +121046,191 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::token_iterator>::simdjson_result(lasx::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::token_iterator>(std::forward<lasx::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(lasx::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::parser>(std::forward<lasx::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for lasx */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for lasx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
-  return get<T>().get(out);
-}
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;pos < target.size() && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  // if the content has no escape character, just scan through it quickly!
+  for(;target[pos] && target[pos] != '\\';pos++) {}
+  // slow path may begin.
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if((target[pos] == '"') && !escaping) {
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
     }
-    default:
-      return raw_json_token();
   }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
+}
+
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
   }
 }
 
@@ -116909,253 +121240,360 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
-  lasx::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(
-      std::forward<lasx::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string>::simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::raw_json_string>(std::forward<lasx::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.raw();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lasx::ondemand::raw_json_string>::unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
   if (error()) { return error(); }
-  return first.count_fields();
+  return first.unescape(iter, allow_replacement);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lasx::ondemand::raw_json_string>::unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.unescape_wobbly(iter);
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
+/* including simdjson/generic/ondemand/serialization-inl.h for lasx: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
+
+
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace lasx::ondemand;
+  lasx::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      lasx::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      lasx::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+} // namespace simdjson
+
+namespace simdjson { namespace lasx { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lasx::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::lasx::ondemand
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for lasx */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return static_cast<T>(first);
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
+simdjson_inline simdjson_result<lasx::ondemand::token_iterator>::simdjson_result(lasx::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::token_iterator>(std::forward<lasx::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for lasx */
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for lasx */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* begin file simdjson/generic/ondemand/value_iterator-inl.h for lasx */
 #ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
@@ -117959,6 +122397,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
   if(result) { // we have something that looks like a null.
     if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
     advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   return result;
 }
@@ -118250,6 +122690,8 @@ simdjson_inline simdjson_result<lasx::ondemand::value_iterator>::simdjson_result
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/value_iterator-inl.h for lasx */
+
+
 /* end file simdjson/generic/ondemand/amalgamated.h for lasx */
 /* including simdjson/lasx/end.h: #include "simdjson/lasx/end.h" */
 /* begin file simdjson/lasx/end.h */
@@ -118290,6 +122732,5 @@ namespace simdjson {
 
 #endif // SIMDJSON_ONDEMAND_H
 /* end file simdjson/ondemand.h */
-
 #endif // SIMDJSON_H
 /* end file simdjson.h */

From f5484b5685d982578933f7bb2534656304af8422 Mon Sep 17 00:00:00 2001
From: "Node.js GitHub Bot" <github-bot@iojs.org>
Date: Sun, 12 Jan 2025 00:34:33 +0000
Subject: [PATCH 2/4] deps: update simdjson to 3.11.5

---
 deps/simdjson/simdjson.cpp |    18 +-
 deps/simdjson/simdjson.h   | 11498 ++++++++++++++++++++++-------------
 2 files changed, 7412 insertions(+), 4104 deletions(-)

diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp
index 83b5b8a5b34a5a..e2e65671e0282d 100644
--- a/deps/simdjson/simdjson.cpp
+++ b/deps/simdjson/simdjson.cpp
@@ -1,4 +1,4 @@
-/* auto-generated on 2024-12-12 10:37:26 -0500. Do not edit! */
+/* auto-generated on 2025-01-08 21:29:11 -0500. Do not edit! */
 /* including simdjson.cpp:  */
 /* begin file simdjson.cpp */
 #define SIMDJSON_SRC_SIMDJSON_CPP
@@ -83,9 +83,20 @@
 #endif
 #endif
 
+#if defined(__apple_build_version__)
+#if __apple_build_version__ < 14000000
+#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
+#endif
+#endif
+
+
 #if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#if __cpp_concepts >= 201907L
 #include <utility>
 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
+#else
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
+#endif
 #else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
 #endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
@@ -102,11 +113,15 @@
 #include <cstdlib>
 #include <cfloat>
 #include <cassert>
+#include <climits>
 #ifndef _WIN32
 // strcasecmp, strncasecmp
 #include <strings.h>
 #endif
 
+static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
+
+
 // We are using size_t without namespace std:: throughout the project
 using std::size_t;
 
@@ -140,6 +155,7 @@ using std::size_t;
 #elif defined(__loongarch_lp64)
 #define SIMDJSON_IS_LOONGARCH64 1
 #elif defined(__PPC64__) || defined(_M_PPC64)
+#define SIMDJSON_IS_PPC64 1
 #if defined(__ALTIVEC__)
 #define SIMDJSON_IS_PPC64_VMX 1
 #endif // defined(__ALTIVEC__)
diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index c80e8cdafc47b0..b3e1265dfd453b 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -1,4 +1,4 @@
-/* auto-generated on 2024-12-12 10:37:26 -0500. Do not edit! */
+/* auto-generated on 2025-01-08 21:29:11 -0500. Do not edit! */
 /* including simdjson.h:  */
 /* begin file simdjson.h */
 #ifndef SIMDJSON_H
@@ -103,9 +103,20 @@
 #endif
 #endif
 
+#if defined(__apple_build_version__)
+#if __apple_build_version__ < 14000000
+#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
+#endif
+#endif
+
+
 #if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#if __cpp_concepts >= 201907L
 #include <utility>
 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
+#else
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
+#endif
 #else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
 #endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
@@ -122,11 +133,15 @@
 #include <cstdlib>
 #include <cfloat>
 #include <cassert>
+#include <climits>
 #ifndef _WIN32
 // strcasecmp, strncasecmp
 #include <strings.h>
 #endif
 
+static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
+
+
 // We are using size_t without namespace std:: throughout the project
 using std::size_t;
 
@@ -160,6 +175,7 @@ using std::size_t;
 #elif defined(__loongarch_lp64)
 #define SIMDJSON_IS_LOONGARCH64 1
 #elif defined(__PPC64__) || defined(_M_PPC64)
+#define SIMDJSON_IS_PPC64 1
 #if defined(__ALTIVEC__)
 #define SIMDJSON_IS_PPC64_VMX 1
 #endif // defined(__ALTIVEC__)
@@ -2421,7 +2437,7 @@ namespace std {
 #define SIMDJSON_SIMDJSON_VERSION_H
 
 /** The version of simdjson being used (major.minor.revision) */
-#define SIMDJSON_VERSION "3.11.3"
+#define SIMDJSON_VERSION "3.11.5"
 
 namespace simdjson {
 enum {
@@ -2436,7 +2452,7 @@ enum {
   /**
    * The revision (major.minor.REVISION) of simdjson being used.
    */
-  SIMDJSON_VERSION_REVISION = 3
+  SIMDJSON_VERSION_REVISION = 5
 };
 } // namespace simdjson
 
@@ -40949,36 +40965,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -40990,7 +41009,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -48603,74 +48622,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number()
   return iter.get_number();
 }
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
 }
 
 simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
@@ -48938,329 +48893,278 @@ simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallb
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for fallback */
-/* including simdjson/generic/ondemand/document-inl.h for fallback: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/value-inl.h for fallback: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
 {
-  logger::log_start_value(iter, "document");
 }
-
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
-}
-
-inline void document::rewind() noexcept {
-  iter.rewind();
-}
-
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
-}
-
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
-}
-
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
 }
-
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
-}
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
 }
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
 }
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
     return get_object();
   } else {
-    return object::resume(resume_value_iterator());
-  }
-}
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
-
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
+    return object::resume(iter);
   }
 }
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
-}
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
-}
-
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
 }
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
 }
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
 }
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
 }
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
 }
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
 }
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
 }
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
 
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
-
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
 #endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
   auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
   return answer;
 }
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
   auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
+  answer = a.count_fields();
+  iter.move_at_start();
   return answer;
 }
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
   auto a = get_array();
   return a.at(index);
 }
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
-}
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
   return start_or_resume_object()[key];
 }
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
   return start_or_resume_object()[key];
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
-  }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
-}
-
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return (this_type == json_type::string);
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
 }
 
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
 }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
   }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t)
@@ -49270,15 +49174,15 @@ simdjson_inline simdjson_result<value> document::at_pointer(std::string_view jso
     case json_type::object:
       return (*this).get_object().at_pointer(json_pointer);
     default:
-      return INVALID_JSON_POINTER;
-  }
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t) {
@@ -49297,699 +49201,1304 @@ simdjson_inline simdjson_result<value> document::at_path(std::string_view json_p
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
-  fallback::ondemand::document &&value
+simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
+  fallback::ondemand::value &&value
 ) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document>(
-      std::forward<fallback::ondemand::document>(value)
+    implementation_simdjson_result_base<fallback::ondemand::value>(
+      std::forward<fallback::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
   error_code error
 ) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document>(
-      error
-    )
+    implementation_simdjson_result_base<fallback::ondemand::value>(error)
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_elements() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at(size_t index) noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::begin() & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::end() & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
   return {};
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(std::string_view key) & noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document>::get_array() & noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::value>::get_array() noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document>::get_object() & noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::value>::get_object() noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::value>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() & noexcept {
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>(fallback::ondemand::value &out) noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  out = first;
+  return SUCCESS;
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() && noexcept {
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::value>::get() noexcept {
   if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first).get<T>();
+  return first.get<T>();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) & noexcept {
+template<typename T> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get(T &out) noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first).get<T>(out);
-}
 
-template<> simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) && noexcept {
+template<> simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>() noexcept  {
   if (error()) { return error(); }
-  out = std::forward<fallback::ondemand::document>(first);
-  return SUCCESS;
+  return std::move(first);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document>::type() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::value>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_string() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-
-simdjson_inline bool simdjson_result<fallback::ondemand::document>::is_negative() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_integer() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document>::get_number_type() noexcept {
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::value>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document>::get_number() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::value>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
-
-
 #if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
+template <class T>
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::array() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::object() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::value() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::value>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.raw_json_token();
 }
 
-simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first.at_end();
+  return first.raw_json();
 }
 
-
-simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_depth() const noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::value>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<int32_t> simdjson_result<fallback::ondemand::value>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for fallback */
+/* including simdjson/generic/ondemand/document-inl.h for fallback: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-
-
-namespace simdjson {
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::simdjson_result(fallback::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<fallback::ondemand::document_reference>(std::forward<fallback::ondemand::document_reference>(value), error) {}
-
-
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
+{
+  logger::log_start_value(iter, "document");
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+
+inline void document::rewind() noexcept {
+  iter.rewind();
 }
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
 }
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::end() & noexcept {
-  return {};
+
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
+    return get_object();
+  } else {
+    return object::resume(resume_value_iterator());
+  }
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
+
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
 }
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
+}
+
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
+
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
+}
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
+
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
+
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
+
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
+
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
+
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
+}
+
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+}
+
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+  fallback::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::document>(
+      std::forward<fallback::ondemand::document>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::document>(
+      error
+    )
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
+
 template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() & noexcept {
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
 template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() && noexcept {
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() && noexcept {
   if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document_reference>(first).get<T>();
+  return std::forward<fallback::ondemand::document>(first).get<T>();
 }
-template <class T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) & noexcept {
+template<typename T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-template <class T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) && noexcept {
+template<typename T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document_reference>(first).get<T>(out);
+  return std::forward<fallback::ondemand::document>(first).get<T>(out);
 }
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document_reference>::type() noexcept {
+
+template<> simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return std::forward<fallback::ondemand::document>(first);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_scalar() noexcept {
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) && noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  out = std::forward<fallback::ondemand::document>(first);
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_string() noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
-  return first.is_string();
+  return first.type();
 }
-template <>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) & noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_scalar();
 }
-template <>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) && noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<fallback::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document_reference>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document_reference>::get_number() noexcept {
+
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, fallback::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, fallback::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first.get<T>();
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::array() & noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::object() & noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::value() noexcept(false) {
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document_reference>::current_location() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::raw_json_token() noexcept {
+simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
+}
+
+
+simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
   return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for fallback */
-/* including simdjson/generic/ondemand/document_stream-inl.h for fallback: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <algorithm>
-#include <stdexcept>
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
-
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
-
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
-
-
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
-}
-
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+
+
+namespace simdjson {
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::simdjson_result(fallback::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<fallback::ondemand::document_reference>(std::forward<fallback::ondemand::document_reference>(value), error) {}
+
+
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>(out);
+}
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, fallback::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, fallback::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for fallback */
+/* including simdjson/generic/ondemand/document_stream-inl.h for fallback: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
+}
+
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
+}
+
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
+}
+
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
+
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
   _next_batch_start = next_batch_start;
   stage1_thread_parser = stage1;
   has_work = true;
@@ -51922,36 +52431,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -51963,7 +52475,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -52054,28 +52566,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace fallback
@@ -52083,343 +52629,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(fallback::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(std::forward<fallback::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
+  fallback::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape_wobbly(fallback::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
-/* including simdjson/generic/ondemand/serialization-inl.h for fallback: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace fallback {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace fallback::ondemand;
-  fallback::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      fallback::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      fallback::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace fallback { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::fallback::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::fallback::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for fallback */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -52428,10 +52866,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(fallback::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(std::forward<fallback::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -52453,6 +52891,7 @@ simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_re
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace fallback {
 namespace ondemand {
 
@@ -52532,6 +52971,7 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
+} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -60054,6 +60494,496 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
+  haswell::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::value>(
+      std::forward<haswell::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -60961,7 +61891,7 @@ simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswe
 template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -63387,36 +64317,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -63428,7 +64361,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -63519,28 +64452,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace haswell
@@ -63548,343 +64515,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(haswell::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(std::forward<haswell::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
+  haswell::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape_wobbly(haswell::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
-/* including simdjson/generic/ondemand/serialization-inl.h for haswell: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace haswell {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace haswell::ondemand;
-  haswell::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      haswell::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      haswell::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace haswell { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::haswell::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::haswell::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for haswell */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -63893,10 +64752,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(haswell::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(std::forward<haswell::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -63918,6 +64777,7 @@ simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_res
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace haswell {
 namespace ondemand {
 
@@ -71512,6 +72372,496 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  icelake::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(
+      std::forward<icelake::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -72419,7 +73769,7 @@ simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icela
 template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<icelake::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -74845,36 +76195,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -74886,7 +76239,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -74977,28 +76330,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace icelake
@@ -75006,343 +76393,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(std::forward<icelake::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
+  icelake::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
-/* including simdjson/generic/ondemand/serialization-inl.h for icelake: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace icelake::ondemand;
-  icelake::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      icelake::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      icelake::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace icelake { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::icelake::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::icelake::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for icelake */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -75351,10 +76630,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(icelake::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(std::forward<icelake::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -75376,6 +76655,7 @@ simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_res
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace icelake {
 namespace ondemand {
 
@@ -75455,6 +76735,7 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
+} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -83091,6 +84372,496 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
+  ppc64::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::value>(
+      std::forward<ppc64::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<ppc64::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/value-inl.h for ppc64: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -83998,7 +85769,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::
 template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -86424,36 +88195,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -86465,7 +88239,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -86556,28 +88330,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace ppc64
@@ -86585,343 +88393,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(std::forward<ppc64::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
+  ppc64::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/serialization-inl.h for ppc64: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace ppc64::ondemand;
-  ppc64::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      ppc64::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      ppc64::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace ppc64 { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::ppc64::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::ppc64::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -86930,10 +88630,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(std::forward<ppc64::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -86955,6 +88655,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_resul
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace ppc64 {
 namespace ondemand {
 
@@ -94987,6 +96688,496 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
+  westmere::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(
+      std::forward<westmere::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -95894,7 +98085,7 @@ simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<west
 template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<westmere::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -98320,36 +100511,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -98361,7 +100555,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -98452,28 +100646,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace westmere
@@ -98481,343 +100709,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(std::forward<westmere::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
+  westmere::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
-/* including simdjson/generic/ondemand/serialization-inl.h for westmere: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace westmere::ondemand;
-  westmere::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      westmere::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      westmere::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace westmere { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::westmere::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::westmere::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for westmere */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -98826,10 +100946,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(westmere::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(std::forward<westmere::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -98851,6 +100971,7 @@ simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_re
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace westmere {
 namespace ondemand {
 
@@ -98930,6 +101051,7 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
+} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -106360,6 +108482,496 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+  lsx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(
+      std::forward<lsx::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -107267,7 +109879,7 @@ simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::onde
 template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<lsx::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -109693,36 +112305,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
   return true;
 }
@@ -109734,7 +112349,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -109825,28 +112440,62 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
-  return iter.unescape(*this, allow_replacement);
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
-  return iter.unescape_wobbly(*this);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
-  bool in_escape = false;
-  const char *s = str.raw();
-  while (true) {
-    switch (*s) {
-      case '\\': in_escape = !in_escape; break;
-      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
-      default: if (in_escape) { in_escape = false; }
-    }
-    out << *s;
-    s++;
-  }
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace lsx
@@ -109854,343 +112503,235 @@ simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, cons
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(std::forward<lsx::ondemand::raw_json_string>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
+  lsx::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
+{
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::raw_json_string>::raw() const noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.raw();
+  return *first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape(iter, allow_replacement);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept {
-  if (error()) { return error(); }
-  return first.unescape_wobbly(iter);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
+// Checks for ']' and ','
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
-/* including simdjson/generic/ondemand/serialization-inl.h for lsx: #include "simdjson/generic/ondemand/serialization-inl.h" */
-/* begin file simdjson/generic/ondemand/serialization-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-inline std::string_view trim(const std::string_view str) noexcept {
-  // We can almost surely do better by rolling our own find_first_not_of function.
-  size_t first = str.find_first_not_of(" \t\n\r");
-  // If we have the empty string (just white space), then no trimming is possible, and
-  // we return the empty string_view.
-  if (std::string_view::npos == first) { return std::string_view(); }
-  size_t last = str.find_last_not_of(" \t\n\r");
-  return str.substr(first, (last - first + 1));
-}
-
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document_reference& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept {
-  /**
-   * If we somehow receive a value that has already been consumed,
-   * then the following code could be in trouble. E.g., we create
-   * an array as needed, but if an array was already created, then
-   * it could be bad.
-   */
-  using namespace lsx::ondemand;
-  lsx::ondemand::json_type t;
-  auto error = x.type().get(t);
-  if(error != SUCCESS) { return error; }
-  switch (t)
-  {
-    case json_type::array:
-    {
-      lsx::ondemand::array array;
-      error = x.get_array().get(array);
-      if(error) { return error; }
-      return to_json_string(array);
-    }
-    case json_type::object:
-    {
-      lsx::ondemand::object object;
-      error = x.get_object().get(object);
-      if(error) { return error; }
-      return to_json_string(object);
-    }
-    default:
-      return trim(x.raw_json_token());
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
-}
-
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept {
-  std::string_view v;
-  auto error = x.raw_json().get(v);
-  if(error) {return error; }
-  return trim(v);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document_reference> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  json.remove_utf8_bom();
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x) {
-  if (x.error()) { return x.error(); }
-  return to_json_string(x.value_unsafe());
-}
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson { namespace lsx { namespace ondemand {
+  json.remove_utf8_bom();
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(x).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
-}
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
-  }
-}
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x) {
-  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
-#endif
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    throw simdjson::simdjson_error(error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
-inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lsx::ondemand::object> x) {
-  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
-  return (out << x.value());
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
-#else
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
-  std::string_view v;
-  auto error = simdjson::to_json_string(value).get(v);
-  if(error == simdjson::SUCCESS) {
-    return (out << v);
-  } else {
-    return (out << error);
-  }
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
-#endif
-}}} // namespace simdjson::lsx::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
-/* end file simdjson/generic/ondemand/serialization-inl.h for lsx */
-/* including simdjson/generic/ondemand/token_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+  json.remove_utf8_bom();
 
-simdjson_inline token_iterator::token_iterator(
-  const uint8_t *_buf,
-  token_position position
-) noexcept : buf{_buf}, _position{position}
-{
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
-  return *(_position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-
-simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
-  return &buf[*(_position++)];
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
-  return &buf[*position];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
-  return *position;
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
-  return *(position+1) - *position;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
-  return *(position+2) - *(position) > *(position+1) - *(position) ?
-      *(position+1) - *(position)
-      : *(position+2) - *(position);
-}
-simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
-  return &buf[*(_position+delta)];
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
-  return *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
-  return *(_position+delta+1) - *(_position+delta);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline token_position token_iterator::position() const noexcept {
-  return _position;
-}
-simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
-  _position = target_position;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
-  return _position == other._position;
-}
-simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
-  return _position != other._position;
-}
-simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
-  return _position > other._position;
-}
-simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
-  return _position >= other._position;
-}
-simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
-  return _position < other._position;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
-simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
-  return _position <= other._position;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -110199,10 +112740,10 @@ simdjson_inline bool token_iterator::operator<=(const token_iterator &other) con
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(lsx::ondemand::token_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(std::forward<lsx::ondemand::token_iterator>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
@@ -110224,6 +112765,7 @@ simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace lsx {
 namespace ondemand {
 
@@ -110303,6 +112845,7 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
+} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -117746,6 +120289,500 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+  lasx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(
+      std::forward<lasx::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -119364,1711 +122401,1903 @@ inline void document_stream::next() noexcept {
     }
   }
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
 }
-
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
-
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
-
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
-{
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  lasx::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
-      std::forward<lasx::ondemand::document_stream>(value)
-    )
-{
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first).get<T>();
 }
-
+template<typename T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
-/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
-
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+template<typename T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first).get<T>(out);
 }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+template<> simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document>(first);
 }
-
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<lasx::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
 
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline bool simdjson_result<lasx::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  lasx::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(
-      std::forward<lasx::ondemand::field>(value)
-    )
-{
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(error)
-{
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+simdjson_inline bool simdjson_result<lasx::ondemand::document>::at_end() const noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return first.at_end();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+
+simdjson_inline int32_t simdjson_result<lasx::ondemand::document>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.raw_json_token();
 }
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_path(std::string_view json_path) noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
-}
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
-}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
-}
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+namespace simdjson {
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::simdjson_result(lasx::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<lasx::ondemand::document_reference>(std::forward<lasx::ondemand::document_reference>(value), error) {}
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
-}
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::document_reference>(first).get<T>(out);
+}
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, lasx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, lasx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
 
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
 
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+  return first.at_path(json_path);
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
+} // namespace simdjson
 
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for lasx */
+/* including simdjson/generic/ondemand/document_stream-inl.h for lasx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
-}
+#include <algorithm>
+#include <stdexcept>
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
-}
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
   }
-  return reinterpret_cast<const char *>(token.peek());
+#endif
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
 
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
-}
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
 }
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
   }
-  return TAPE_ERROR;
-}
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
 
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-#endif
+#ifdef SIMDJSON_THREADS_ENABLED
 
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
 
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
 }
 
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
 
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  lasx::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
+      std::forward<lasx::ondemand::document_stream>(value)
+    )
+{
+}
 
-} // namespace simdjson
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
+/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-#endif
 
-
-
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
-}
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  lasx::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(
+      std::forward<lasx::ondemand::field>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(error)
+{
 }
 
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+  if (error()) { return error(); }
+  return first.key();
 }
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+  if (error()) { return error(); }
+  return first.escaped_key();
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(allow_replacement);
+}
 
-namespace simdjson {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
+}
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
-/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
-
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
-}
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
 {
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+  other.parser = nullptr;
 }
-
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
 
-static inline log_level log_threshold()
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
+
 {
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 
-static inline bool should_log(log_level level)
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
 {
-  return level >= log_threshold();
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
-}
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
-}
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
-}
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
-}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
-/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
   }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
-}
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(lasx::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::object>(std::forward<lasx::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first).find_field_unordered(key);
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first)[key];
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::object>(first).find_field(key);
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
   }
-  return first.at_path(json_path);
+  return TAPE_ERROR;
 }
 
-inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
 
-inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
+
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for lasx */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-//
-// object_iterator
-//
-
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
-SIMDJSON_POP_DISABLE_WARNINGS
+#endif
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
 
-namespace simdjson {
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
+}
 
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(
-  lasx::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>(std::forward<lasx::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>({}, error)
-{
+
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::field> simdjson_result<lasx::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator==(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator!=(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &simdjson_result<lasx::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-} // namespace simdjson
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/parser-inl.h for lasx: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
+}
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
+}
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
+}
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-  json.remove_utf8_bom();
+namespace simdjson {
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
+/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  json.remove_utf8_bom();
+#include <memory>
+#include <cstring>
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+namespace logger {
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
+
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
   }
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
+} // namespace logger
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(lasx::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::parser>(std::forward<lasx::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for lasx */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for lasx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
+/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace lasx {
 namespace ondemand {
 
@@ -121079,132 +124308,195 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;pos < target.size() && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
-  return true;
+  return value(iter.child());
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
   size_t pos{0};
-  // if the content has no escape character, just scan through it quickly!
-  for(;target[pos] && target[pos] != '\\';pos++) {}
-  // slow path may begin.
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if((target[pos] == '"') && !escaping) {
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
-  return true;
+  return value(iter.child());
 }
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
+  // Assumptions: does not contain unescaped quote characters("), and
   // the raw content is quote terminated within a valid JSON string.
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
   }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return value(iter.child());
 }
 
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
+}
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
+}
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
+}
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
 
 simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {

From 8c0e4cb81f468168114a869d580a64af20713456 Mon Sep 17 00:00:00 2001
From: "Node.js GitHub Bot" <github-bot@iojs.org>
Date: Sun, 19 Jan 2025 00:32:59 +0000
Subject: [PATCH 3/4] deps: update simdjson to 3.11.6

---
 deps/simdjson/simdjson.cpp |     2 +-
 deps/simdjson/simdjson.h   | 54034 +++++++++++++++++++----------------
 2 files changed, 29180 insertions(+), 24856 deletions(-)

diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp
index e2e65671e0282d..9fda730019dabb 100644
--- a/deps/simdjson/simdjson.cpp
+++ b/deps/simdjson/simdjson.cpp
@@ -1,4 +1,4 @@
-/* auto-generated on 2025-01-08 21:29:11 -0500. Do not edit! */
+/* auto-generated on 2025-01-09 11:01:48 -0500. Do not edit! */
 /* including simdjson.cpp:  */
 /* begin file simdjson.cpp */
 #define SIMDJSON_SRC_SIMDJSON_CPP
diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index b3e1265dfd453b..3589214b4584a0 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -1,4 +1,4 @@
-/* auto-generated on 2025-01-08 21:29:11 -0500. Do not edit! */
+/* auto-generated on 2025-01-09 11:01:48 -0500. Do not edit! */
 /* including simdjson.h:  */
 /* begin file simdjson.h */
 #ifndef SIMDJSON_H
@@ -2437,7 +2437,7 @@ namespace std {
 #define SIMDJSON_SIMDJSON_VERSION_H
 
 /** The version of simdjson being used (major.minor.revision) */
-#define SIMDJSON_VERSION "3.11.5"
+#define SIMDJSON_VERSION "3.11.6"
 
 namespace simdjson {
 enum {
@@ -2452,7 +2452,7 @@ enum {
   /**
    * The revision (major.minor.REVISION) of simdjson being used.
    */
-  SIMDJSON_VERSION_REVISION = 5
+  SIMDJSON_VERSION_REVISION = 6
 };
 } // namespace simdjson
 
@@ -48608,496 +48608,6 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
-  fallback::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::value>(
-      std::forward<fallback::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>(fallback::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<fallback::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-
-template<> simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::get<fallback::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator fallback::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline simdjson_result<int32_t> simdjson_result<fallback::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/value-inl.h for fallback: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -49925,11 +49435,12 @@ simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::docume
 }
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.get_value();
+  return first.is_null();
 }
 simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  out = first;
+  return SUCCESS;
 }
 
 template<typename T>
@@ -50005,11 +49516,11 @@ simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fall
 template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -50048,7 +49559,7 @@ simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback
 
 simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.raw_json_token();
 }
 
 simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
@@ -50064,12 +49575,12 @@ simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_d
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.raw_json();
 }
 
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.current_location();
 }
 
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
@@ -50532,300 +50043,287 @@ simdjson_inline document_stream::document_stream(
   if(worker.get() == nullptr) {
     error = MEMALLOC;
   }
-#endif
 }
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
-}
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
-}
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
   }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
 
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
 
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace fallback
@@ -50833,1149 +50331,1161 @@ inline void document_stream::start_stage1_thread() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+  fallback::ondemand::document &&value
 ) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document_stream>(error)
+    implementation_simdjson_result_base<fallback::ondemand::document>(
+      std::forward<fallback::ondemand::document>(value)
+    )
 {
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
-  fallback::ondemand::document_stream &&value
+simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document_stream>(
-      std::forward<fallback::ondemand::document_stream>(value)
+    implementation_simdjson_result_base<fallback::ondemand::document>(
+      error
     )
 {
 }
-
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for fallback */
-/* including simdjson/generic/ondemand/field-inl.h for fallback: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
-
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-
 template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
-  fallback::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::field>(
-      std::forward<fallback::ondemand::field>(value)
-    )
-{
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::field>(error)
-{
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document>(first).get<T>();
 }
-
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::field>::key() noexcept {
+template<typename T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.get<T>(out);
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document>(first).get<T>(out);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::key_raw_json_token() noexcept {
+template<> simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return std::forward<fallback::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<fallback::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::escaped_key() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.type();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.is_scalar();
 }
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.is_string();
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::field>::value() noexcept {
+simdjson_inline bool simdjson_result<fallback::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.is_negative();
 }
 
-} // namespace simdjson
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for fallback */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
-}
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
 }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
+} // namespace simdjson
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
-}
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
-}
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
-}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
+namespace simdjson {
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::simdjson_result(fallback::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<fallback::ondemand::document_reference>(std::forward<fallback::ondemand::document_reference>(value), error) {}
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
 }
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
+simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
 }
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
 }
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template <class T>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::document_reference>(first).get<T>(out);
+}
+simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, fallback::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, fallback::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
 #endif
 
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
 
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
 
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
   }
-  return true;
+  return first.at_path(json_path);
 }
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(fallback::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(std::forward<fallback::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(error) {}
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/json_type-inl.h for fallback: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for fallback */
+/* including simdjson/generic/ondemand/document_stream-inl.h for fallback: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <algorithm>
+#include <stdexcept>
+
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
-
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
-}
-#endif
-
-
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
 }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
+}
 
-namespace simdjson {
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
+}
 
-simdjson_inline simdjson_result<fallback::ondemand::json_type>::simdjson_result(fallback::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_type>(std::forward<fallback::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_type>(error) {}
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-} // namespace simdjson
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for fallback */
-/* including simdjson/generic/ondemand/logger-inl.h for fallback: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
 
-#include <memory>
-#include <cstring>
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
+}
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-namespace logger {
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
+}
 
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+}
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
   } else {
-    return ' ';
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
   }
 }
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
-}
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
-}
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
-}
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+#endif // SIMDJSON_THREADS_ENABLED
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::document_stream>(error)
+{
 }
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
+  fallback::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::document_stream>(
+      std::forward<fallback::ondemand::document_stream>(value)
+    )
+{
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for fallback */
+/* including simdjson/generic/ondemand/field-inl.h for fallback: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
-}
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
       }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
+  return true;
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
-}
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for fallback */
-/* including simdjson/generic/ondemand/object-inl.h for fallback: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
   }
-  return value(iter.child());
-}
-
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
-}
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
-}
-
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
-}
-
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
-}
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
-}
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
 } // namespace ondemand
@@ -51984,412 +51494,486 @@ simdjson_inline simdjson_result<bool> object::reset() & noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::object>::simdjson_result(fallback::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::object>(std::forward<fallback::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator> simdjson_result<fallback::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator> simdjson_result<fallback::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::object>(first).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::object>(first)[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
+  fallback::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::field>(
+      std::forward<fallback::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::object>(first).find_field(key);
+simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::field>(error)
+{
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.key();
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
 
-inline simdjson_result<bool> simdjson_result<fallback::ondemand::object>::reset() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.reset();
+  return first.escaped_key();
 }
 
-inline simdjson_result<bool> simdjson_result<fallback::ondemand::object>::is_empty() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<fallback::ondemand::object>::count_fields() & noexcept {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.count_fields();
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<fallback::ondemand::object>::raw_json() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return std::move(first.value());
 }
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for fallback */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for fallback */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-//
-// object_iterator
-//
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
+}
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
+}
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
+
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
+}
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-namespace simdjson {
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
 
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
-  fallback::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
-{
-}
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
 
-simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-} // namespace simdjson
+SIMDJSON_POP_DISABLE_WARNINGS
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
+}
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
+}
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+}
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
+}
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
+}
 
-  json.remove_utf8_bom();
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
+}
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
   }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
   }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+  return reinterpret_cast<const char *>(token.peek());
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
+}
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
   }
+  return TAPE_ERROR;
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+}
+
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
+}
+
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
 
 } // namespace ondemand
@@ -52398,38 +51982,346 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(fallback::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(std::forward<fallback::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for fallback */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for fallback: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
+}
+
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
+}
+
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
+
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
+
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
+
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+
+  // If the loop ended, we're out of fields to look at.
+  return false;
+}
+
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
+
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
+
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+}
+
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
+}
+
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for fallback */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for fallback: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
   while(pos < target.size()) {
     pos = target.find('"', pos);
@@ -52807,11 +52699,48 @@ simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iter
   return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
   }
   if(allow_comma_separated && batch_size < len) { batch_size = len; }
   return document_stream(*this, buf, len, batch_size, allow_comma_separated);
@@ -53102,20 +53031,49 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_
   // If we don't find a match, we may loop back around, and scan from the beginning to that point.
   token_position search_start = _json_iter->position();
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
+
+
+/* end file simdjson/generic/ondemand/amalgamated.h for fallback */
+/* including simdjson/fallback/end.h: #include "simdjson/fallback/end.h" */
+/* begin file simdjson/fallback/end.h */
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/fallback/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+/* undefining SIMDJSON_IMPLEMENTATION from "fallback" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/fallback/end.h */
+
+#endif // SIMDJSON_FALLBACK_ONDEMAND_H
+/* end file simdjson/fallback/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
+/* including simdjson/haswell/ondemand.h: #include "simdjson/haswell/ondemand.h" */
+/* begin file simdjson/haswell/ondemand.h */
+#ifndef SIMDJSON_HASWELL_ONDEMAND_H
+#define SIMDJSON_HASWELL_ONDEMAND_H
+
+/* including simdjson/haswell/begin.h: #include "simdjson/haswell/begin.h" */
+/* begin file simdjson/haswell/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "haswell" */
+#define SIMDJSON_IMPLEMENTATION haswell
+
+/* including simdjson/haswell/base.h: #include "simdjson/haswell/base.h" */
+/* begin file simdjson/haswell/base.h */
+#ifndef SIMDJSON_HASWELL_BASE_H
+#define SIMDJSON_HASWELL_BASE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_HASWELL
+namespace simdjson {
+/**
+ * Implementation for Haswell (Intel AVX2).
+ */
+namespace haswell {
 
   // 2. When a previous search did not yield a value or the object is empty:
   //
@@ -53254,27 +53212,15 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_
       return true;
     }
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+// We enable bmi2 only if LLVM/clang is used, because GCC may not
+// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
+#if defined(__clang__)
+SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
+#else
+SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
+#endif
+#endif
 
 simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
   assert_at_next();
@@ -55472,13 +55418,137 @@ class value {
    */
   simdjson_inline simdjson_result<array> get_array() noexcept;
 
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for haswell */
+/* including simdjson/generic/ondemand/deserialize.h for haswell: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for haswell */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<haswell::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = haswell::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = haswell::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = haswell::ondemand::value;
+  using document_type = haswell::ondemand::document;
+  using document_reference_type = haswell::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for haswell */
+/* including simdjson/generic/ondemand/value_iterator.h for haswell: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
   /**
    * Cast this JSON value to an unsigned integer.
@@ -56431,13 +56501,16 @@ struct simdjson_result<haswell::ondemand::token_iterator> : public haswell::impl
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace haswell {
 namespace ondemand {
-
 /**
  * Iterates through JSON tokens, keeping track of depth and string buffer.
  *
@@ -56472,32 +56545,50 @@ class json_iterator {
    * - 2 = , or } inside root array/object
    * - 3 = key or value inside root array/object.
    */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
-   */
-  bool _streaming{false};
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+
 
-public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
    * Skips a JSON value, whether it is a scalar, array or object.
    */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
    * Tell whether the iterator is still at the start
@@ -56570,10 +56661,20 @@ class json_iterator {
    *
    * This is not null-terminated; it is a view into the JSON.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
   simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
@@ -56858,19 +56959,15 @@ struct number {
    * functions on a number type. They are protected and should never be used outside
    * of the core simdjson library.
    */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
+
   /**
    * End of friend declarations.
    */
@@ -57093,13 +57190,14 @@ class raw_json_string {
    *
    * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
-};
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) noexcept = delete;
 
 simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
 
@@ -58130,12 +58228,25 @@ class document {
   /**
    * Cast this JSON value to an array.
    *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
    *
    * @returns An object that can be used to look up or iterate fields.
    * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
@@ -58360,43 +58471,13 @@ class document {
    *
    * @returns true if the number if negative.
    */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  bool threaded{true};
+  #else
   /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
+  bool threaded{false};
+  #endif
   /**
    * Attempt to parse an ondemand::number. An ondemand::number may
    * contain an integer value or a floating-point value, the simdjson
@@ -58466,7 +58547,19 @@ class document {
   inline bool is_alive() noexcept;
 
   /**
-   * Returns the current location in the document if in bounds.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   *
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
   inline simdjson_result<const char *> current_location() const noexcept;
 
@@ -58898,16 +58991,11 @@ struct simdjson_result<haswell::ondemand::document_reference> : public haswell::
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
 
 namespace simdjson {
 namespace haswell {
@@ -59012,92 +59100,74 @@ class document_stream {
    *   size_t truncated = stream.truncated_bytes();
    *
    */
-  inline size_t truncated_bytes() const noexcept;
-
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
-
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
-
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
-
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
-
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
-
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
   /**
    * Start iterating the documents in the stream.
    */
-  simdjson_inline iterator begin() noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+
+#if SIMDJSON_EXCEPTIONS
   /**
    * The end of the stream, for iterator comparison purposes.
    */
@@ -59291,10 +59361,16 @@ class field : public std::pair<raw_json_string, value> {
    */
   simdjson_inline raw_json_string key() const noexcept;
   /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
   simdjson_inline std::string_view key_raw_json_token() const noexcept;
   /**
@@ -59457,7 +59533,171 @@ class object {
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
+
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
+  /**
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+
+  /**
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  /**
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
+   */
+  inline void rewind() noexcept;
+  /**
+   * Returns debugging information.
+   */
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
 
   /**
    * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -59573,6 +59813,148 @@ class object {
   friend struct simdjson_result<object>;
 };
 
+
+/**
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
+ */
+class document_reference {
+public:
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+private:
+  document *doc{nullptr};
+};
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
@@ -59589,7 +59971,10 @@ struct simdjson_result<haswell::ondemand::object> : public haswell::implementati
   simdjson_inline simdjson_result<haswell::ondemand::object_iterator> begin() noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::object_iterator> end() noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
@@ -59673,9 +60058,64 @@ struct simdjson_result<haswell::ondemand::object_iterator> : public haswell::imp
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
 
-  //
-  // Iterator interface
-  //
+  simdjson_inline simdjson_result<haswell::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator haswell::ondemand::array() & noexcept(false);
+  simdjson_inline operator haswell::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator haswell::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator haswell::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<haswell::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<haswell::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
 
   // Reads key and value, yielding them to the user.
   simdjson_inline simdjson_result<haswell::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
@@ -60864,15 +61304,679 @@ simdjson_inline simdjson_result<bool> value::is_null() noexcept {
   return iter.is_null();
 }
 
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for haswell: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for haswell */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  haswell::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for haswell */
+
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for haswell: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
+
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
+
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
+
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
 
 template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
@@ -61331,7 +62435,6 @@ simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswel
   return first.at_path(json_path);
 }
 
-} // namespace simdjson
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 /* end file simdjson/generic/ondemand/value-inl.h for haswell */
@@ -61355,9 +62458,23 @@ simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswel
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
   : iter{std::forward<json_iterator>(_iter)}
@@ -61891,7 +63008,7 @@ simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswe
 template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -61934,7 +63051,7 @@ simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::
 
 simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.get<T>();
 }
 
 simdjson_inline bool simdjson_result<haswell::ondemand::document>::at_end() const noexcept {
@@ -61950,7 +63067,7 @@ simdjson_inline int32_t simdjson_result<haswell::ondemand::document>::current_de
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return std::forward<haswell::ondemand::document>(first).get<T>();
 }
 
 simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
@@ -62492,1554 +63609,1474 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++
 simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
   return finished != other.finished;
 }
-
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+template<typename T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document>(first).get<T>(out);
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+template<> simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document>(first);
 }
-
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<haswell::ondemand::document>(first);
+  return SUCCESS;
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
 
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
+simdjson_inline bool simdjson_result<haswell::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
-
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-#endif // SIMDJSON_THREADS_ENABLED
-
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document_stream>(error)
-{
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
-  haswell::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document_stream>(
-      std::forward<haswell::ondemand::document_stream>(value)
-    )
-{
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for haswell */
-/* including simdjson/generic/ondemand/field-inl.h for haswell: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
-
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
-
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline bool simdjson_result<haswell::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
 }
 
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline int32_t simdjson_result<haswell::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
 }
 
+} // namespace simdjson
+
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
 
+
+
 namespace simdjson {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::simdjson_result(haswell::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<haswell::ondemand::document_reference>(std::forward<haswell::ondemand::document_reference>(value), error) {}
 
-simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
-  haswell::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::field>(
-      std::forward<haswell::ondemand::field>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::field>(error)
-{
-}
 
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::field>::key() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_elements() & noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.count_elements();
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::key_raw_json_token() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return first.count_fields();
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::escaped_key() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at(size_t index) & noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.at(index);
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::rewind() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  first.rewind();
+  return SUCCESS;
 }
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.begin();
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.find_field_unordered(key);
 }
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for haswell */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
-
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
 }
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
 }
-
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
 }
-
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
 }
-
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
 }
-
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
 }
-
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+template <typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
-
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>();
 }
-
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>(out);
 }
-
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
-
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, haswell::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, haswell::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
 #endif
-  token.set_position(position);
-  _depth = child_depth;
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
-}
-
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
   }
-  return true;
+  return first.at_path(json_path);
 }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(haswell::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(std::forward<haswell::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(error) {}
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/json_type-inl.h for haswell: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for haswell */
+/* including simdjson/generic/ondemand/document_stream-inl.h for haswell: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <algorithm>
+#include <stdexcept>
+
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
+}
+
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
+}
+
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
     }
-    return out;
+  );
 }
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
+
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
+
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
 #endif
+}
 
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
+}
 
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
+}
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
   }
-  if(is_int64()) {
-    return double(payload.signed_integer);
+}
+
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
+}
+
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+}
+
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
   }
-  return double(payload.unsigned_integer);
 }
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
+
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
+}
+
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(haswell::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_type>(std::forward<haswell::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document_stream>(error)
+{
+}
+simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
+  haswell::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document_stream>(
+      std::forward<haswell::ondemand::document_stream>(value)
+    )
+{
+}
 
-} // namespace simdjson
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for haswell */
-/* including simdjson/generic/ondemand/logger-inl.h for haswell: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for haswell */
+/* including simdjson/generic/ondemand/field-inl.h for haswell: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
-namespace logger {
 
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
-
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
-}
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
 {
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
+  haswell::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::field>(
+      std::forward<haswell::ondemand::field>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::field>(error)
+{
 }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::field>::key() noexcept {
+  if (error()) { return error(); }
+  return first.key();
 }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::escaped_key() noexcept {
+  if (error()) { return error(); }
+  return first.escaped_key();
+}
 
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(allow_replacement);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+template<typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace haswell
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for haswell */
-/* including simdjson/generic/ondemand/object-inl.h for haswell: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for haswell */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
 }
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
+
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
   }
-  return value(iter.child());
+  return count == 0;
 }
 
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
-}
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
   }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
-}
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
 
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+}
 
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
+}
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
+}
 
-namespace simdjson {
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
+}
 
-simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(haswell::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::object>(std::forward<haswell::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::object>(error) {}
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
+}
 
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first).find_field_unordered(key);
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first)[key];
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first).find_field(key);
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
 
-inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
 
-inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for haswell */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
+}
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
+}
 
-//
-// object_iterator
-//
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
+}
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+#if SIMDJSON_DEVELOPMENT_CHECKS
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+#endif
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
+}
 
 } // namespace ondemand
 } // namespace haswell
@@ -64047,266 +65084,379 @@ SIMDJSON_POP_DISABLE_WARNINGS
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
-  haswell::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
+simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(haswell::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(std::forward<haswell::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/json_type-inl.h for haswell: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
 #endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
+}
 
-  json.remove_utf8_bom();
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
+}
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
+}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
+}
+
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
+}
+
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
   }
-  return iterate(padded_string_view(json));
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
+}
 
-  json.remove_utf8_bom();
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(haswell::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_type>(std::forward<haswell::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for haswell */
+/* including simdjson/generic/ondemand/logger-inl.h for haswell: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <memory>
+#include <cstring>
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+namespace logger {
+
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+}
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+}
 
-namespace simdjson {
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
+}
 
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
+}
+
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+}
+
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
+
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
+
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
+} // namespace logger
+} // namespace ondemand
+} // namespace haswell
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for haswell */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for haswell: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for haswell */
+/* including simdjson/generic/ondemand/object-inl.h for haswell: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace haswell {
 namespace ondemand {
 
@@ -64331,7 +65481,40 @@ simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_v
     }
     pos++;
   }
-  return true;
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
@@ -64351,13 +65534,22 @@ simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* t
     }
     pos++;
   }
-  return true;
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
@@ -64375,81 +65567,210 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) c
   return true;
 }
 
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
 
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
+}
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return at_pointer(json_pointer);
 }
 
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(haswell::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::object>(std::forward<haswell::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::object>(first).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::object>(first)[key];
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::object>(first).find_field(key);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::reset() noexcept {
+  if (error()) { return error(); }
+  return first.reset();
+}
+
+inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::is_empty() noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+
+simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::object>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for haswell */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+//
+// object_iterator
+//
+
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
+}
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
 SIMDJSON_PUSH_DISABLE_WARNINGS
@@ -72657,14 +73978,679 @@ simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelak
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for icelake: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for icelake */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  icelake::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for icelake */
+
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for icelake: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  icelake::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(
+      std::forward<icelake::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
@@ -75562,36 +77548,58 @@ namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   return value(iter.child());
 }
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   return value(iter.child());
 }
 simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
   return find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
   }
   return value(iter.child());
 }
@@ -76169,18 +78177,21 @@ simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(erro
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for icelake */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for icelake: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -76188,972 +78199,503 @@ namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
 }
 
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
   }
-  if(r[pos] != '"') { return false; }
   return true;
 }
 
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
     }
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return SUCCESS;
 }
 
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
+}
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
 
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
+
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
       return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
   }
   if(r[pos] != '"') { return false; }
   return true;
 }
 
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
 SIMDJSON_PUSH_DISABLE_WARNINGS
 SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
 
-namespace simdjson {
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
-  icelake::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
   }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-  json.remove_utf8_bom();
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
   }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
 }
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
   assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
     _json_iter->return_current_and_advance();
-    end_container();
+    SIMDJSON_TRY( end_container() );
     return false;
   }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
   return true;
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
   // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
   // current document. It only works in the normal mode where we have indexed a single document.
   // Note that adding a check for 'streaming' is not expensive since we only have at most
   // one root element.
   if ( ! _json_iter->streaming() ) {
     // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
     // ensure that the processing has finished at the end.
     //
-    if (*_json_iter->peek_last() != '}') {
+    if (*_json_iter->peek_last() != ']') {
       _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
     }
-    // If the last character is } *and* the first gibberish character is also '}'
+    // If the last character is ] *and* the first gibberish character is also ']'
     // then on-demand could accidentally go over. So we need additional checks.
     // https://github.com/simdjson/simdjson/issues/1834
     // Checking that the document is balanced requires a full scan which is potentially
     // expensive, but it only happens in edge cases where the first padding character is
     // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
       _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
+      // The exact error would require more work. It will typically be an unclosed array.
       return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
     }
   }
   return SUCCESS;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
 }
-} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
   assert_at_next();
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
+  logger::log_event(*this, "has_next_element");
   switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
       SIMDJSON_TRY( end_container() );
       return false;
     case ',':
+      _json_iter->descend_to(depth()+1);
       return true;
     default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
   }
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
-
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
-
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
-
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
-
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
-
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
-
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
-
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
-
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
-
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
-
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
-
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
-}
-
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
-  return answer;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  return true;
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
-    }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
-
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
+}
 
 simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
   return get_raw_json_string().unescape(json_iter(), allow_replacement);
@@ -84372,496 +85914,6 @@ simdjson_inline simdjson_result<bool> value::is_string() noexcept {
 }
 
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
-  ppc64::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::value>(
-      std::forward<ppc64::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-
-template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-
-template<> simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline simdjson_result<int32_t> simdjson_result<ppc64::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/value-inl.h for ppc64: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
 simdjson_inline bool value::is_negative() noexcept {
   return iter.is_negative();
 }
@@ -85082,7 +86134,8 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::g
 }
 simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  out = first;
+  return SUCCESS;
 }
 
 template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
@@ -85171,7 +86224,6 @@ simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcep
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-#endif
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
   if (error()) { return error(); }
@@ -85612,27 +86664,27 @@ simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.find_field(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field_unordered(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first[key];
 }
 simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
@@ -85689,11 +86741,12 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.get_value();
+  return first.is_null();
 }
 simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  out = first;
+  return SUCCESS;
 }
 
 template<typename T>
@@ -85769,11 +86822,11 @@ simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::
 template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -85812,7 +86865,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::onde
 
 simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.raw_json_token();
 }
 
 simdjson_inline bool simdjson_result<ppc64::ondemand::document>::at_end() const noexcept {
@@ -85828,12 +86881,12 @@ simdjson_inline int32_t simdjson_result<ppc64::ondemand::document>::current_dept
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.raw_json();
 }
 
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.current_location();
 }
 
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_path(std::string_view json_path) noexcept {
@@ -86296,300 +87349,287 @@ simdjson_inline document_stream::document_stream(
   if(worker.get() == nullptr) {
     error = MEMALLOC;
   }
-#endif
 }
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
-}
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
-}
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
   }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
 
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
 
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace ppc64
@@ -86597,1564 +87637,1026 @@ inline void document_stream::start_stage1_thread() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<ppc64::ondemand::document>::simdjson_result(
+  ppc64::ondemand::document &&value
 ) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(error)
+    implementation_simdjson_result_base<ppc64::ondemand::document>(
+      std::forward<ppc64::ondemand::document>(value)
+    )
 {
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
-  ppc64::ondemand::document_stream &&value
+simdjson_inline simdjson_result<ppc64::ondemand::document>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(
-      std::forward<ppc64::ondemand::document_stream>(value)
+    implementation_simdjson_result_base<ppc64::ondemand::document>(
+      error
     )
 {
 }
-
-}
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/field-inl.h for ppc64: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
-
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
-}
-
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
   return SUCCESS;
 }
-
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
-}
-
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
-  ppc64::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::field>(
-      std::forward<ppc64::ondemand::field>(value)
-    )
-{
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::field>(error)
-{
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::field>::key() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.find_field(key);
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::key_raw_json_token() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return first.find_field(key);
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::escaped_key() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.get_array();
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.get_object();
 }
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.get_uint64();
 }
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.get_uint64_in_string();
 }
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
 }
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
 }
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+template <typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document>(first).get<T>();
 }
-
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+template<typename T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+template<typename T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document>(first).get<T>(out);
 }
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+template<> simdjson_inline simdjson_result<ppc64::ondemand::document> simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<ppc64::ondemand::document> simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document>(first);
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>(ppc64::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>(ppc64::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<ppc64::ondemand::document>(first);
+  return SUCCESS;
 }
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+simdjson_inline bool simdjson_result<ppc64::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
-}
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
 #endif
-}
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
-}
 
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
+simdjson_inline bool simdjson_result<ppc64::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
 }
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
 
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+simdjson_inline int32_t simdjson_result<ppc64::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
 }
 
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
 }
 
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(std::forward<ppc64::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(error) {}
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/json_type-inl.h for ppc64: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
-
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
 #if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
-}
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
 #endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
-}
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
-}
+namespace simdjson {
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::simdjson_result(ppc64::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<ppc64::ondemand::document_reference>(std::forward<ppc64::ondemand::document_reference>(value), error) {}
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
-}
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(ppc64::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(std::forward<ppc64::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/logger-inl.h for ppc64: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <memory>
-#include <cstring>
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
-
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
+simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
 }
-
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
 }
-
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
 }
-
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
 }
-
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
 }
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
 }
-
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+template <typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
-
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
-}
-
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
-}
-
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
-}
-
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document_reference>(first).get<T>();
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+template <class T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-
-} // namespace logger
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/object-inl.h for ppc64: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+template <class T>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::document_reference>(first).get<T>(out);
 }
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+template <>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+template <>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
+simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
-
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, ppc64::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, ppc64::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(ppc64::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::object>(std::forward<ppc64::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first)[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document_reference>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.current_location();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) && noexcept {
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first).find_field(key);
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
   if (error()) {
-    return error();
+      return error();
   }
   return first.at_path(json_path);
 }
 
-inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
-}
-
-inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
-
-simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/document_stream-inl.h for ppc64: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <algorithm>
+#include <stdexcept>
+
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-//
-// object_iterator
-//
-
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
+}
 
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
 
-namespace simdjson {
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
 
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
-  ppc64::ondemand::object_iterator &&value
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
+
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
 ) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
 {
-  first.iter.assert_is_valid();
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
 }
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
 {
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
+}
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+}
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
+}
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
   }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-  json.remove_utf8_bom();
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
   }
+}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
   }
-  return iterate(padded_string_view(json));
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+#ifdef SIMDJSON_THREADS_ENABLED
 
-  json.remove_utf8_bom();
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
+#endif // SIMDJSON_THREADS_ENABLED
 
 } // namespace ondemand
 } // namespace ppc64
@@ -88162,230 +88664,100 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(error)
+{
+}
+simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
+  ppc64::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(
+      std::forward<ppc64::ondemand::document_stream>(value)
+    )
+{
+}
 
-} // namespace simdjson
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/field-inl.h for ppc64: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
-}
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
 
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
 
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
 
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
 
 } // namespace ondemand
 } // namespace ppc64
@@ -88393,235 +88765,486 @@ SIMDJSON_POP_DISABLE_WARNINGS
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
-  ppc64::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
+simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
+  ppc64::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::field>(
+      std::forward<ppc64::ondemand::field>(value)
+    )
 {
-  first.iter.assert_is_valid();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::field>(error)
 {
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.key();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::escaped_key() noexcept {
+  if (error()) { return error(); }
+  return first.escaped_key();
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(allow_replacement);
+}
+
+template<typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
+}
+
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 
 #ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 #endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
   }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+  return count == 0;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-  json.remove_utf8_bom();
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
+}
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
   }
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
+}
+
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
+}
+
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
+}
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
+}
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
+}
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
+}
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
+}
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
+}
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
+}
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
+}
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
+}
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
+}
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
+}
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
+}
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
+}
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
+}
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
   return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
   return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
+}
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
+}
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
+}
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+}
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+}
+
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
+}
+
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
 
 } // namespace ondemand
@@ -88630,1096 +89253,775 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(std::forward<ppc64::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/json_type-inl.h for ppc64: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
+#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
+}
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
+}
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
+}
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
+}
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
   }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
+}
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
+}
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
+}
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
+}
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
+namespace simdjson {
 
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(ppc64::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(std::forward<ppc64::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(error) {}
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
+} // namespace simdjson
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/logger-inl.h for ppc64: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+#include <memory>
+#include <cstring>
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+namespace logger {
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
-
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
-  return answer;
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  return true;
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
-    }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
-
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
+
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
+
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
+
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
+
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
+
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
-  }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
-simdjson_inline simdjson_result<ppc64::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
     }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
   }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
+
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
+
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
   }
-  return result;
 }
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
+} // namespace logger
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/object-inl.h for ppc64: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
-  return result;
+  return value(iter.child());
 }
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
-  return result;
+  return value(iter.child());
 }
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
   }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
-  return result;
+  if(r[pos] != '"') { return false; }
+  return true;
 }
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  return result;
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
   }
-  return result;
+  return value(iter.child());
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
-
-  return _json_iter->skip_child(depth());
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
 }
-
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
 }
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
 }
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
-
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
-
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
-  }
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
+}
 
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
 
-  return SUCCESS;
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+namespace simdjson {
 
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(ppc64::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::object>(std::forward<ppc64::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::object>(error) {}
 
-  assert_at_non_root_start();
-  return _json_iter->peek();
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
 }
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::object>(first).find_field_unordered(key);
 }
-
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::object>(first)[key];
 }
-
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::object>(first).find_field(key);
 }
 
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
+inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::reset() noexcept {
+  if (error()) { return error(); }
+  return first.reset();
 }
 
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
+inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::is_empty() noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
 }
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
+simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::object>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
+} // namespace simdjson
 
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
+//
+// object_iterator
+//
 
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
-  }
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
 }
-
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
+
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace ppc64
@@ -89727,2744 +90029,2693 @@ simdjson_inline error_code value_iterator::report_error(error_code error, const
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::value_iterator>::simdjson_result(ppc64::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::value_iterator>(std::forward<ppc64::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::value_iterator>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
+  ppc64::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+{
+}
 
-} // namespace simdjson
+simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
+} // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
-/* end file simdjson/generic/ondemand/amalgamated.h for ppc64 */
-/* including simdjson/ppc64/end.h: #include "simdjson/ppc64/end.h" */
-/* begin file simdjson/ppc64/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
-/* undefining SIMDJSON_IMPLEMENTATION from "ppc64" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/ppc64/end.h */
-
-#endif // SIMDJSON_PPC64_ONDEMAND_H
-/* end file simdjson/ppc64/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
-/* including simdjson/westmere/ondemand.h: #include "simdjson/westmere/ondemand.h" */
-/* begin file simdjson/westmere/ondemand.h */
-#ifndef SIMDJSON_WESTMERE_ONDEMAND_H
-#define SIMDJSON_WESTMERE_ONDEMAND_H
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-/* including simdjson/westmere/begin.h: #include "simdjson/westmere/begin.h" */
-/* begin file simdjson/westmere/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "westmere" */
-#define SIMDJSON_IMPLEMENTATION westmere
-/* including simdjson/westmere/base.h: #include "simdjson/westmere/base.h" */
-/* begin file simdjson/westmere/base.h */
-#ifndef SIMDJSON_WESTMERE_BASE_H
-#define SIMDJSON_WESTMERE_BASE_H
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_WESTMERE
-namespace simdjson {
-/**
- * Implementation for Westmere (Intel SSE4.2).
- */
-namespace westmere {
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+  }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
+}
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+}
+#endif
 
-class implementation;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace {
-namespace simd {
+  json.remove_utf8_bom();
 
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-} // namespace simd
-} // unnamed namespace
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+}
 
-} // namespace westmere
-} // namespace simdjson
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-#endif // SIMDJSON_WESTMERE_BASE_H
-/* end file simdjson/westmere/base.h */
-/* including simdjson/westmere/intrinsics.h: #include "simdjson/westmere/intrinsics.h" */
-/* begin file simdjson/westmere/intrinsics.h */
-#ifndef SIMDJSON_WESTMERE_INTRINSICS_H
-#define SIMDJSON_WESTMERE_INTRINSICS_H
+  json.remove_utf8_bom();
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-#if SIMDJSON_VISUAL_STUDIO
-// under clang within visual studio, this will include <x86intrin.h>
-#include <intrin.h> // visual studio or clang
-#else
-#include <x86intrin.h> // elsewhere
-#endif // SIMDJSON_VISUAL_STUDIO
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+}
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
 
-#if SIMDJSON_CLANG_VISUAL_STUDIO
-/**
- * You are not supposed, normally, to include these
- * headers directly. Instead you should either include intrin.h
- * or x86intrin.h. However, when compiling with clang
- * under Windows (i.e., when _MSC_VER is set), these headers
- * only get included *if* the corresponding features are detected
- * from macros:
- */
-#include <smmintrin.h>  // for _mm_alignr_epi8
-#include <wmmintrin.h>  // for  _mm_clmulepi64_si128
-#endif
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
 
-static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for westmere");
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
+}
 
-#endif // SIMDJSON_WESTMERE_INTRINSICS_H
-/* end file simdjson/westmere/intrinsics.h */
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
+}
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
-SIMDJSON_TARGET_REGION("sse4.2,pclmul,popcnt")
-#endif
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
+}
 
-/* including simdjson/westmere/bitmanipulation.h: #include "simdjson/westmere/bitmanipulation.h" */
-/* begin file simdjson/westmere/bitmanipulation.h */
-#ifndef SIMDJSON_WESTMERE_BITMANIPULATION_H
-#define SIMDJSON_WESTMERE_BITMANIPULATION_H
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-namespace simdjson {
-namespace westmere {
-namespace {
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long ret;
-  // Search the mask data from least significant bit (LSB)
-  // to the most significant bit (MSB) for a set bit (1).
-  _BitScanForward64(&ret, input_num);
-  return (int)ret;
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO
-  return __builtin_ctzll(input_num);
-#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
-}
+  json.remove_utf8_bom();
 
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num-1);
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long leading_zero = 0;
-  // Search the mask data from most significant bit (MSB)
-  // to least significant bit (LSB) for a set bit (1).
-  if (_BitScanReverse64(&leading_zero, input_num))
-    return (int)(63 - leading_zero);
-  else
-    return 64;
-#else
-  return __builtin_clzll(input_num);
-#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
-  // note: we do not support legacy 32-bit Windows in this kernel
-  return __popcnt64(input_num);// Visual Studio wants two underscores
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-#else
-simdjson_inline long long int count_ones(uint64_t input_num) {
-  return _popcnt64(input_num);
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-#endif
-
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
-                                uint64_t *result) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  return _addcarry_u64(0, value1, value2,
-                       reinterpret_cast<unsigned __int64 *>(result));
-#else
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-#endif
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-} // unnamed namespace
-} // namespace westmere
-} // namespace simdjson
-
-#endif // SIMDJSON_WESTMERE_BITMANIPULATION_H
-/* end file simdjson/westmere/bitmanipulation.h */
-/* including simdjson/westmere/bitmask.h: #include "simdjson/westmere/bitmask.h" */
-/* begin file simdjson/westmere/bitmask.h */
-#ifndef SIMDJSON_WESTMERE_BITMASK_H
-#define SIMDJSON_WESTMERE_BITMASK_H
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
+}
 
-namespace simdjson {
-namespace westmere {
-namespace {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
 
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
-  // There should be no such thing with a processing supporting avx2
-  // but not clmul.
-  __m128i all_ones = _mm_set1_epi8('\xFF');
-  __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
-  return _mm_cvtsi128_si64(result);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-} // unnamed namespace
-} // namespace westmere
+} // namespace ondemand
+} // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_WESTMERE_BITMASK_H
-/* end file simdjson/westmere/bitmask.h */
-/* including simdjson/westmere/numberparsing_defs.h: #include "simdjson/westmere/numberparsing_defs.h" */
-/* begin file simdjson/westmere/numberparsing_defs.h */
-#ifndef SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
-#define SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
-
-/* including simdjson/westmere/base.h: #include "simdjson/westmere/base.h" */
-/* begin file simdjson/westmere/base.h */
-#ifndef SIMDJSON_WESTMERE_BASE_H
-#define SIMDJSON_WESTMERE_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_WESTMERE
 namespace simdjson {
-/**
- * Implementation for Westmere (Intel SSE4.2).
- */
-namespace westmere {
-
-class implementation;
-
-namespace {
-namespace simd {
-
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
 
-} // namespace simd
-} // unnamed namespace
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
 
-} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_WESTMERE_BASE_H
-/* end file simdjson/westmere/base.h */
-/* including simdjson/westmere/intrinsics.h: #include "simdjson/westmere/intrinsics.h" */
-/* begin file simdjson/westmere/intrinsics.h */
-#ifndef SIMDJSON_WESTMERE_INTRINSICS_H
-#define SIMDJSON_WESTMERE_INTRINSICS_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#if SIMDJSON_VISUAL_STUDIO
-// under clang within visual studio, this will include <x86intrin.h>
-#include <intrin.h> // visual studio or clang
-#else
-#include <x86intrin.h> // elsewhere
-#endif // SIMDJSON_VISUAL_STUDIO
-
-
-#if SIMDJSON_CLANG_VISUAL_STUDIO
-/**
- * You are not supposed, normally, to include these
- * headers directly. Instead you should either include intrin.h
- * or x86intrin.h. However, when compiling with clang
- * under Windows (i.e., when _MSC_VER is set), these headers
- * only get included *if* the corresponding features are detected
- * from macros:
- */
-#include <smmintrin.h>  // for _mm_alignr_epi8
-#include <wmmintrin.h>  // for  _mm_clmulepi64_si128
-#endif
-
-static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for westmere");
+namespace simdjson {
 
-#endif // SIMDJSON_WESTMERE_INTRINSICS_H
-/* end file simdjson/westmere/intrinsics.h */
+namespace ppc64 {
+namespace ondemand {
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
+}
 
-namespace simdjson {
-namespace westmere {
-namespace numberparsing {
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
+}
 
-/** @private */
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  // this actually computes *16* values so we are being wasteful.
-  const __m128i ascii0 = _mm_set1_epi8('0');
-  const __m128i mul_1_10 =
-      _mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
-  const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
-  const __m128i mul_1_10000 =
-      _mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
-  const __m128i input = _mm_sub_epi8(
-      _mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
-  const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
-  const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
-  const __m128i t3 = _mm_packus_epi32(t2, t2);
-  const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
-  return _mm_cvtsi128_si32(
-      t4); // only captures the sum of the first 8 digits, drop the rest
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-/** @private */
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-#if SIMDJSON_IS_ARM64
-  // ARM64 has native support for 64-bit multiplications, no need to emultate
-  answer.high = __umulh(value1, value2);
-  answer.low = value1 * value2;
-#else
-  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
-#endif // SIMDJSON_IS_ARM64
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
 #endif
-  return answer;
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
 }
 
-} // namespace numberparsing
-} // namespace westmere
-} // namespace simdjson
-
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-
-#endif //  SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
-/* end file simdjson/westmere/numberparsing_defs.h */
-/* including simdjson/westmere/simd.h: #include "simdjson/westmere/simd.h" */
-/* begin file simdjson/westmere/simd.h */
-#ifndef SIMDJSON_WESTMERE_SIMD_H
-#define SIMDJSON_WESTMERE_SIMD_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace {
-namespace simd {
-
-  template<typename Child>
-  struct base {
-    __m128i value;
-
-    // Zero constructor
-    simdjson_inline base() : value{__m128i()} {}
-
-    // Conversion from SIMD register
-    simdjson_inline base(const __m128i _value) : value(_value) {}
-
-    // Conversion to SIMD register
-    simdjson_inline operator const __m128i&() const { return this->value; }
-    simdjson_inline operator __m128i&() { return this->value; }
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
+}
 
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return _mm_or_si128(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return _mm_and_si128(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return _mm_xor_si128(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return _mm_andnot_si128(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
+}
 
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    typedef uint16_t bitmask_t;
-    typedef uint32_t bitmask2_t;
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
+}
 
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
 
-    friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
+}
 
-    static const int SIZE = sizeof(base<simd8<T>>::value);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-      return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
-    }
-  };
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
 
-    simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
-    simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
+  // If the loop ended, we're out of fields to look at.
+  return false;
+}
 
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) { return _mm_set1_epi8(_value); }
-    static simdjson_inline simd8<T> zero() { return _mm_setzero_si128(); }
-    static simdjson_inline simd8<T> load(const T values[16]) {
-      return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
 
-    // Store to array
-    simdjson_inline void store(T dst[16]) const { return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this); }
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm_add_epi8(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm_sub_epi8(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
 
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return _mm_shuffle_epi8(lookup_table, *this);
-    }
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
-    // get written.
-    // Design consideration: it seems like a function with the
-    // signature simd8<L> compress(uint32_t mask) would be
-    // sensible, but the AVX ISA makes this kind of approach difficult.
-    template<typename L>
-    simdjson_inline void compress(uint16_t mask, L * output) const {
-      using internal::thintable_epi8;
-      using internal::BitsSetTable256mul2;
-      using internal::pshufb_combine_table;
-      // this particular implementation was inspired by work done by @animetosho
-      // we do it in two steps, first 8 bytes and then second 8 bytes
-      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
-      uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
-      // next line just loads the 64-bit values thintable_epi8[mask1] and
-      // thintable_epi8[mask2] into a 128-bit register, using only
-      // two instructions on most compilers.
-      __m128i shufmask =  _mm_set_epi64x(thintable_epi8[mask2], thintable_epi8[mask1]);
-      // we increment by 0x08 the second half of the mask
-      shufmask =
-      _mm_add_epi8(shufmask, _mm_set_epi32(0x08080808, 0x08080808, 0, 0));
-      // this is the version "nearly pruned"
-      __m128i pruned = _mm_shuffle_epi8(*this, shufmask);
-      // we still need to put the two halves together.
-      // we compute the popcount of the first half:
-      int pop1 = BitsSetTable256mul2[mask1];
-      // then load the corresponding mask, what it does is to write
-      // only the first pop1 bytes from the first 8 bytes, and then
-      // it fills in with the bytes from the second 8 bytes + some filling
-      // at the end.
-      __m128i compactmask =
-      _mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop1 * 8));
-      __m128i answer = _mm_shuffle_epi8(pruned, compactmask);
-      _mm_storeu_si128(reinterpret_cast<__m128i *>(output), answer);
-    }
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
-  };
 
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) : simd8(_mm_setr_epi8(
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    )) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm_max_epi8(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm_min_epi8(*this, other); }
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(*this, other); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(other, *this); }
-  };
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t* values) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) : simd8(_mm_setr_epi8(
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    )) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
+
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
 
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm_adds_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm_subs_epu8(*this, other); }
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
+  }
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm_max_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm_min_epu8(*this, other); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
 
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
-    simdjson_inline bool is_ascii() const { return _mm_movemask_epi8(*this) == 0; }
-    simdjson_inline bool bits_not_set_anywhere() const { return _mm_testz_si128(*this, *this); }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return _mm_testz_si128(*this, bits); }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
-    // Get one of the bits and make a bitmask out of it.
-    // e.g. value.get_bit<7>() gets the high bit
-    template<int N>
-    simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); }
-  };
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
+}
 
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
 
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
+}
 
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
+}
 
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
-      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
-      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
-    }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
+}
 
-    simdjson_inline simd8<T> reduce_or() const {
-      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
-    }
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
+}
 
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      this->chunks[0].compress(uint16_t(mask), output);
-      this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
-      this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
-      this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
-      return 64 - count_ones(mask);
-    }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
+  }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  return true;
+}
 
-    simdjson_inline uint64_t to_bitmask() const {
-      uint64_t r0 = uint32_t(this->chunks[0].to_bitmask() );
-      uint64_t r1 =          this->chunks[1].to_bitmask() ;
-      uint64_t r2 =          this->chunks[2].to_bitmask() ;
-      uint64_t r3 =          this->chunks[3].to_bitmask() ;
-      return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
     }
-
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] == mask,
-        this->chunks[1] == mask,
-        this->chunks[2] == mask,
-        this->chunks[3] == mask
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return  simd8x64<bool>(
-        this->chunks[0] == other.chunks[0],
-        this->chunks[1] == other.chunks[1],
-        this->chunks[2] == other.chunks[2],
-        this->chunks[3] == other.chunks[3]
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] <= mask,
-        this->chunks[1] <= mask,
-        this->chunks[2] <= mask,
-        this->chunks[3] <= mask
-      ).to_bitmask();
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
     }
-  }; // struct simd8x64<T>
+  }
+  return SUCCESS;
+}
 
-} // namespace simd
-} // unnamed namespace
-} // namespace westmere
-} // namespace simdjson
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
+}
 
-#endif // SIMDJSON_WESTMERE_SIMD_INPUT_H
-/* end file simdjson/westmere/simd.h */
-/* including simdjson/westmere/stringparsing_defs.h: #include "simdjson/westmere/stringparsing_defs.h" */
-/* begin file simdjson/westmere/stringparsing_defs.h */
-#ifndef SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
-#define SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-/* including simdjson/westmere/bitmanipulation.h: #include "simdjson/westmere/bitmanipulation.h" */
-/* begin file simdjson/westmere/bitmanipulation.h */
-#ifndef SIMDJSON_WESTMERE_BITMANIPULATION_H
-#define SIMDJSON_WESTMERE_BITMANIPULATION_H
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
+  }
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
+}
 
-namespace simdjson {
-namespace westmere {
-namespace {
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
+}
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
+}
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
+}
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
+  if(error) { return error; }
+  return num;
+}
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long ret;
-  // Search the mask data from least significant bit (LSB)
-  // to the most significant bit (MSB) for a set bit (1).
-  _BitScanForward64(&ret, input_num);
-  return (int)ret;
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO
-  return __builtin_ctzll(input_num);
-#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+  }
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
 }
 
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num-1);
+simdjson_inline simdjson_result<ppc64::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
+}
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
+  if(error) { return error; }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
+}
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long leading_zero = 0;
-  // Search the mask data from most significant bit (MSB)
-  // to least significant bit (LSB) for a set bit (1).
-  if (_BitScanReverse64(&leading_zero, input_num))
-    return (int)(63 - leading_zero);
-  else
-    return 64;
-#else
-  return __builtin_clzll(input_num);
-#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
-  // note: we do not support legacy 32-bit Windows in this kernel
-  return __popcnt64(input_num);// Visual Studio wants two underscores
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
-#else
-simdjson_inline long long int count_ones(uint64_t input_num) {
-  return _popcnt64(input_num);
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
 }
-#endif
 
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
-                                uint64_t *result) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  return _addcarry_u64(0, value1, value2,
-                       reinterpret_cast<unsigned __int64 *>(result));
-#else
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-#endif
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
 }
 
-} // unnamed namespace
-} // namespace westmere
-} // namespace simdjson
-
-#endif // SIMDJSON_WESTMERE_BITMANIPULATION_H
-/* end file simdjson/westmere/bitmanipulation.h */
-/* including simdjson/westmere/simd.h: #include "simdjson/westmere/simd.h" */
-/* begin file simdjson/westmere/simd.h */
-#ifndef SIMDJSON_WESTMERE_SIMD_H
-#define SIMDJSON_WESTMERE_SIMD_H
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  return _json_iter->skip_child(depth());
+}
 
-namespace simdjson {
-namespace westmere {
-namespace {
-namespace simd {
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
+}
 
-  template<typename Child>
-  struct base {
-    __m128i value;
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-    // Zero constructor
-    simdjson_inline base() : value{__m128i()} {}
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
+}
 
-    // Conversion from SIMD register
-    simdjson_inline base(const __m128i _value) : value(_value) {}
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
+}
 
-    // Conversion to SIMD register
-    simdjson_inline operator const __m128i&() const { return this->value; }
-    simdjson_inline operator __m128i&() { return this->value; }
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
+}
 
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return _mm_or_si128(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return _mm_and_si128(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return _mm_xor_si128(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return _mm_andnot_si128(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
+}
 
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    typedef uint16_t bitmask_t;
-    typedef uint32_t bitmask2_t;
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
+}
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
+}
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
+}
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
+}
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
+}
 
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
+}
 
-    friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
 
-    static const int SIZE = sizeof(base<simd8<T>>::value);
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
+}
 
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-      return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
-    }
-  };
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
 
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
 
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+  } else {
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
+  }
 
-    simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
-    simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
 
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) { return _mm_set1_epi8(_value); }
-    static simdjson_inline simd8<T> zero() { return _mm_setzero_si128(); }
-    static simdjson_inline simd8<T> load(const T values[16]) {
-      return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  return SUCCESS;
+}
 
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
 
-    // Store to array
-    simdjson_inline void store(T dst[16]) const { return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this); }
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  assert_at_root();
+  return _json_iter->peek();
+}
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm_add_epi8(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm_sub_epi8(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
+  assert_at_non_root_start();
+  return _json_iter->peek();
+}
 
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return _mm_shuffle_epi8(lookup_table, *this);
-    }
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
-    // get written.
-    // Design consideration: it seems like a function with the
-    // signature simd8<L> compress(uint32_t mask) would be
-    // sensible, but the AVX ISA makes this kind of approach difficult.
-    template<typename L>
-    simdjson_inline void compress(uint16_t mask, L * output) const {
-      using internal::thintable_epi8;
-      using internal::BitsSetTable256mul2;
-      using internal::pshufb_combine_table;
-      // this particular implementation was inspired by work done by @animetosho
-      // we do it in two steps, first 8 bytes and then second 8 bytes
-      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
-      uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
-      // next line just loads the 64-bit values thintable_epi8[mask1] and
-      // thintable_epi8[mask2] into a 128-bit register, using only
-      // two instructions on most compilers.
-      __m128i shufmask =  _mm_set_epi64x(thintable_epi8[mask2], thintable_epi8[mask1]);
-      // we increment by 0x08 the second half of the mask
-      shufmask =
-      _mm_add_epi8(shufmask, _mm_set_epi32(0x08080808, 0x08080808, 0, 0));
-      // this is the version "nearly pruned"
-      __m128i pruned = _mm_shuffle_epi8(*this, shufmask);
-      // we still need to put the two halves together.
-      // we compute the popcount of the first half:
-      int pop1 = BitsSetTable256mul2[mask1];
-      // then load the corresponding mask, what it does is to write
-      // only the first pop1 bytes from the first 8 bytes, and then
-      // it fills in with the bytes from the second 8 bytes + some filling
-      // at the end.
-      __m128i compactmask =
-      _mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop1 * 8));
-      __m128i answer = _mm_shuffle_epi8(pruned, compactmask);
-      _mm_storeu_si128(reinterpret_cast<__m128i *>(output), answer);
-    }
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
-    }
-  };
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
 
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) : simd8(_mm_setr_epi8(
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    )) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
+}
 
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm_max_epi8(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm_min_epi8(*this, other); }
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(*this, other); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(other, *this); }
-  };
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
+}
 
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t* values) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) : simd8(_mm_setr_epi8(
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    )) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
+}
 
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm_adds_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm_subs_epu8(*this, other); }
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
+}
 
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm_max_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm_min_epu8(*this, other); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
+}
 
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
-    simdjson_inline bool is_ascii() const { return _mm_movemask_epi8(*this) == 0; }
-    simdjson_inline bool bits_not_set_anywhere() const { return _mm_testz_si128(*this, *this); }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return _mm_testz_si128(*this, bits); }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
-    // Get one of the bits and make a bitmask out of it.
-    // e.g. value.get_bit<7>() gets the high bit
-    template<int N>
-    simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); }
-  };
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
+}
 
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
+}
 
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
+}
 
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
+}
 
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
-      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
-      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
-    }
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
+}
 
-    simdjson_inline simd8<T> reduce_or() const {
-      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
-    }
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
+}
 
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      this->chunks[0].compress(uint16_t(mask), output);
-      this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
-      this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
-      this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
-      return 64 - count_ones(mask);
-    }
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
+}
 
-    simdjson_inline uint64_t to_bitmask() const {
-      uint64_t r0 = uint32_t(this->chunks[0].to_bitmask() );
-      uint64_t r1 =          this->chunks[1].to_bitmask() ;
-      uint64_t r2 =          this->chunks[2].to_bitmask() ;
-      uint64_t r3 =          this->chunks[3].to_bitmask() ;
-      return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
-    }
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
+}
 
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] == mask,
-        this->chunks[1] == mask,
-        this->chunks[2] == mask,
-        this->chunks[3] == mask
-      ).to_bitmask();
-    }
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
+}
 
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return  simd8x64<bool>(
-        this->chunks[0] == other.chunks[0],
-        this->chunks[1] == other.chunks[1],
-        this->chunks[2] == other.chunks[2],
-        this->chunks[3] == other.chunks[3]
-      ).to_bitmask();
-    }
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
+}
 
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] <= mask,
-        this->chunks[1] <= mask,
-        this->chunks[2] <= mask,
-        this->chunks[3] <= mask
-      ).to_bitmask();
-    }
-  }; // struct simd8x64<T>
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
+}
 
-} // namespace simd
-} // unnamed namespace
-} // namespace westmere
-} // namespace simdjson
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
+  }
+}
 
-#endif // SIMDJSON_WESTMERE_SIMD_INPUT_H
-/* end file simdjson/westmere/simd.h */
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
+}
 
-namespace simdjson {
-namespace westmere {
-namespace {
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
+}
 
-using namespace simd;
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
+}
 
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 32;
-  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
+}
 
-  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
-  simdjson_inline bool has_backslash() { return bs_bits != 0; }
-  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
-  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
+}
 
-  uint32_t bs_bits;
-  uint32_t quote_bits;
-}; // struct backslash_and_quote
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
-simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 31 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v0(src);
-  simd8<uint8_t> v1(src + 16);
-  v0.store(dst);
-  v1.store(dst + 16);
-  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
-  return {
-    uint32_t(bs_and_quote),      // bs_bits
-    uint32_t(bs_and_quote >> 32) // quote_bits
-  };
-}
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::value_iterator>::simdjson_result(ppc64::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::value_iterator>(std::forward<ppc64::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::value_iterator>(error) {}
 
-} // unnamed namespace
-} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
-/* end file simdjson/westmere/stringparsing_defs.h */
-/* end file simdjson/westmere/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for westmere: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for westmere */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
-#endif
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
 
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for westmere: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
+/* end file simdjson/generic/ondemand/amalgamated.h for ppc64 */
+/* including simdjson/ppc64/end.h: #include "simdjson/ppc64/end.h" */
+/* begin file simdjson/ppc64/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace westmere {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
+#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
+/* undefining SIMDJSON_IMPLEMENTATION from "ppc64" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/ppc64/end.h */
 
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
+#endif // SIMDJSON_PPC64_ONDEMAND_H
+/* end file simdjson/ppc64/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
+/* including simdjson/westmere/ondemand.h: #include "simdjson/westmere/ondemand.h" */
+/* begin file simdjson/westmere/ondemand.h */
+#ifndef SIMDJSON_WESTMERE_ONDEMAND_H
+#define SIMDJSON_WESTMERE_ONDEMAND_H
 
-/** @copydoc simdjson::westmere::number_type */
-using number_type = simdjson::westmere::number_type;
+/* including simdjson/westmere/begin.h: #include "simdjson/westmere/begin.h" */
+/* begin file simdjson/westmere/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "westmere" */
+#define SIMDJSON_IMPLEMENTATION westmere
+/* including simdjson/westmere/base.h: #include "simdjson/westmere/base.h" */
+/* begin file simdjson/westmere/base.h */
+#ifndef SIMDJSON_WESTMERE_BASE_H
+#define SIMDJSON_WESTMERE_BASE_H
 
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
+// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_WESTMERE
+namespace simdjson {
+/**
+ * Implementation for Westmere (Intel SSE4.2).
+ */
+namespace westmere {
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+class implementation;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for westmere */
-/* including simdjson/generic/ondemand/deserialize.h for westmere: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for westmere */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
+namespace {
+namespace simd {
 
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
 
-#include <concepts>
-namespace simdjson {
+} // namespace simd
+} // unnamed namespace
 
-namespace tag_invoke_fn_ns {
-void tag_invoke();
+} // namespace westmere
+} // namespace simdjson
 
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
+#endif // SIMDJSON_WESTMERE_BASE_H
+/* end file simdjson/westmere/base.h */
+/* including simdjson/westmere/intrinsics.h: #include "simdjson/westmere/intrinsics.h" */
+/* begin file simdjson/westmere/intrinsics.h */
+#ifndef SIMDJSON_WESTMERE_INTRINSICS_H
+#define SIMDJSON_WESTMERE_INTRINSICS_H
 
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
+#if SIMDJSON_VISUAL_STUDIO
+// under clang within visual studio, this will include <x86intrin.h>
+#include <intrin.h> // visual studio or clang
+#else
+#include <x86intrin.h> // elsewhere
+#endif // SIMDJSON_VISUAL_STUDIO
 
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
 
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+#if SIMDJSON_CLANG_VISUAL_STUDIO
+/**
+ * You are not supposed, normally, to include these
+ * headers directly. Instead you should either include intrin.h
+ * or x86intrin.h. However, when compiling with clang
+ * under Windows (i.e., when _MSC_VER is set), these headers
+ * only get included *if* the corresponding features are detected
+ * from macros:
+ */
+#include <smmintrin.h>  // for _mm_alignr_epi8
+#include <wmmintrin.h>  // for  _mm_clmulepi64_si128
+#endif
 
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for westmere");
 
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+#endif // SIMDJSON_WESTMERE_INTRINSICS_H
+/* end file simdjson/westmere/intrinsics.h */
 
+#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
+SIMDJSON_TARGET_REGION("sse4.2,pclmul,popcnt")
+#endif
 
-struct deserialize_tag;
+/* including simdjson/westmere/bitmanipulation.h: #include "simdjson/westmere/bitmanipulation.h" */
+/* begin file simdjson/westmere/bitmanipulation.h */
+#ifndef SIMDJSON_WESTMERE_BITMANIPULATION_H
+#define SIMDJSON_WESTMERE_BITMANIPULATION_H
 
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<westmere::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<westmere::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<westmere::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<westmere::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+namespace simdjson {
+namespace westmere {
+namespace {
 
-template <typename T, typename ValT = westmere::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long ret;
+  // Search the mask data from least significant bit (LSB)
+  // to the most significant bit (MSB) for a set bit (1).
+  _BitScanForward64(&ret, input_num);
+  return (int)ret;
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO
+  return __builtin_ctzll(input_num);
+#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
+}
 
-template <typename T, typename ValT = westmere::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num-1);
+}
 
-template <typename T, typename ValT = westmere::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long leading_zero = 0;
+  // Search the mask data from most significant bit (MSB)
+  // to least significant bit (LSB) for a set bit (1).
+  if (_BitScanReverse64(&leading_zero, input_num))
+    return (int)(63 - leading_zero);
+  else
+    return 64;
+#else
+  return __builtin_clzll(input_num);
+#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
+}
 
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = westmere::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
+  // note: we do not support legacy 32-bit Windows in this kernel
+  return __popcnt64(input_num);// Visual Studio wants two underscores
+}
+#else
+simdjson_inline long long int count_ones(uint64_t input_num) {
+  return _popcnt64(input_num);
+}
+#endif
 
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = westmere::ondemand::value;
-  using document_type = westmere::ondemand::document;
-  using document_reference_type = westmere::ondemand::document_reference;
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
+                                uint64_t *result) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  return _addcarry_u64(0, value1, value2,
+                       reinterpret_cast<unsigned __int64 *>(result));
+#else
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
+#endif
+}
 
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
+} // unnamed namespace
+} // namespace westmere
+} // namespace simdjson
 
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
+#endif // SIMDJSON_WESTMERE_BITMANIPULATION_H
+/* end file simdjson/westmere/bitmanipulation.h */
+/* including simdjson/westmere/bitmask.h: #include "simdjson/westmere/bitmask.h" */
+/* begin file simdjson/westmere/bitmask.h */
+#ifndef SIMDJSON_WESTMERE_BITMASK_H
+#define SIMDJSON_WESTMERE_BITMASK_H
 
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+namespace simdjson {
+namespace westmere {
+namespace {
 
-} deserialize{};
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
+  // There should be no such thing with a processing supporting avx2
+  // but not clmul.
+  __m128i all_ones = _mm_set1_epi8('\xFF');
+  __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
+  return _mm_cvtsi128_si64(result);
+}
 
+} // unnamed namespace
+} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+#endif // SIMDJSON_WESTMERE_BITMASK_H
+/* end file simdjson/westmere/bitmask.h */
+/* including simdjson/westmere/numberparsing_defs.h: #include "simdjson/westmere/numberparsing_defs.h" */
+/* begin file simdjson/westmere/numberparsing_defs.h */
+#ifndef SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
+#define SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
 
-/* end file simdjson/generic/ondemand/deserialize.h for westmere */
-/* including simdjson/generic/ondemand/value_iterator.h for westmere: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* including simdjson/westmere/base.h: #include "simdjson/westmere/base.h" */
+/* begin file simdjson/westmere/base.h */
+#ifndef SIMDJSON_WESTMERE_BASE_H
+#define SIMDJSON_WESTMERE_BASE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_WESTMERE
 namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
 /**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
- *
- * @private This is not intended for external use.
+ * Implementation for Westmere (Intel SSE4.2).
  */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
+namespace westmere {
 
-public:
-  simdjson_inline value_iterator() noexcept = default;
+class implementation;
 
-  /**
-   * Denote that we're starting a document.
-   */
-  simdjson_inline void start_document() noexcept;
+namespace {
+namespace simd {
 
-  /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
-   *
-   * Optimized for scalars.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
 
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
+} // namespace simd
+} // unnamed namespace
 
-  /**
-   * Tell whether the iterator is at the start of the value
-   */
-  simdjson_inline bool at_start() const noexcept;
+} // namespace westmere
+} // namespace simdjson
 
-  /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
-   */
-  simdjson_inline bool is_open() const noexcept;
+#endif // SIMDJSON_WESTMERE_BASE_H
+/* end file simdjson/westmere/base.h */
+/* including simdjson/westmere/intrinsics.h: #include "simdjson/westmere/intrinsics.h" */
+/* begin file simdjson/westmere/intrinsics.h */
+#ifndef SIMDJSON_WESTMERE_INTRINSICS_H
+#define SIMDJSON_WESTMERE_INTRINSICS_H
 
-  /**
-   * Tell whether the value is at an object's first field (just after the {).
-   */
-  simdjson_inline bool at_first_field() const noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Abandon all iteration.
-   */
-  simdjson_inline void abandon() noexcept;
+#if SIMDJSON_VISUAL_STUDIO
+// under clang within visual studio, this will include <x86intrin.h>
+#include <intrin.h> // visual studio or clang
+#else
+#include <x86intrin.h> // elsewhere
+#endif // SIMDJSON_VISUAL_STUDIO
 
-  /**
-   * Get the child value as a value_iterator.
-   */
-  simdjson_inline value_iterator child_value() const noexcept;
 
-  /**
-   * Get the depth of this value.
-   */
-  simdjson_inline int32_t depth() const noexcept;
+#if SIMDJSON_CLANG_VISUAL_STUDIO
+/**
+ * You are not supposed, normally, to include these
+ * headers directly. Instead you should either include intrin.h
+ * or x86intrin.h. However, when compiling with clang
+ * under Windows (i.e., when _MSC_VER is set), these headers
+ * only get included *if* the corresponding features are detected
+ * from macros:
+ */
+#include <smmintrin.h>  // for _mm_alignr_epi8
+#include <wmmintrin.h>  // for  _mm_clmulepi64_si128
+#endif
 
-  /**
-   * Get the JSON type of this value.
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
+static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for westmere");
 
-  /**
-   * @addtogroup object Object iteration
-   *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
-   *
-   * @{
-   */
+#endif // SIMDJSON_WESTMERE_INTRINSICS_H
+/* end file simdjson/westmere/intrinsics.h */
 
-  /**
-   * Start an object iteration.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
-  /**
-   * Start an object iteration from the root.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
-  /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
-   *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
-  /**
-   * Start an object iteration after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
-  /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Moves to the next field in an object.
-   *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+namespace simdjson {
+namespace westmere {
+namespace numberparsing {
 
-  /**
-   * Get the current field's key.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
+/** @private */
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  // this actually computes *16* values so we are being wasteful.
+  const __m128i ascii0 = _mm_set1_epi8('0');
+  const __m128i mul_1_10 =
+      _mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
+  const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
+  const __m128i mul_1_10000 =
+      _mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
+  const __m128i input = _mm_sub_epi8(
+      _mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
+  const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
+  const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
+  const __m128i t3 = _mm_packus_epi32(t2, t2);
+  const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
+  return _mm_cvtsi128_si32(
+      t4); // only captures the sum of the first 8 digits, drop the rest
+}
 
-  /**
-   * Pass the : in the field and move to its value.
-   */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
+/** @private */
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+#if SIMDJSON_IS_ARM64
+  // ARM64 has native support for 64-bit multiplications, no need to emultate
+  answer.high = __umulh(value1, value2);
+  answer.low = value1 * value2;
+#else
+  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
+#endif // SIMDJSON_IS_ARM64
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
+#endif
+  return answer;
+}
 
-  /**
-   * Find the next field with the given key.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
+} // namespace numberparsing
+} // namespace westmere
+} // namespace simdjson
 
-  /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
 
-  /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
-   *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
+#endif //  SIMDJSON_WESTMERE_NUMBERPARSING_DEFS_H
+/* end file simdjson/westmere/numberparsing_defs.h */
+/* including simdjson/westmere/simd.h: #include "simdjson/westmere/simd.h" */
+/* begin file simdjson/westmere/simd.h */
+#ifndef SIMDJSON_WESTMERE_SIMD_H
+#define SIMDJSON_WESTMERE_SIMD_H
 
-  /** @} */
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
-   */
+namespace simdjson {
+namespace westmere {
+namespace {
+namespace simd {
 
-  /**
-   * Check for an opening [ and start an array iteration.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
-  /**
-   * Check for an opening [ and start an array iteration while at the root.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
-  /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
-   *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
-  /**
-   * Start an array iteration, after the user has already checked and moved past the [.
-   *
-   * Does not move the iterator unless the array is empty ([]).
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
-  /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
-   *
-   * Does not move the iterator unless the array is empty ([]).
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
+  template<typename Child>
+  struct base {
+    __m128i value;
 
-  /**
-   * Moves to the next element in an array.
-   *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
+    // Zero constructor
+    simdjson_inline base() : value{__m128i()} {}
 
-  /**
-   * Get a child value iterator.
-   */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
+    // Conversion from SIMD register
+    simdjson_inline base(const __m128i _value) : value(_value) {}
 
-  /** @} */
+    // Conversion to SIMD register
+    simdjson_inline operator const __m128i&() const { return this->value; }
+    simdjson_inline operator __m128i&() { return this->value; }
 
-  /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
-   */
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return _mm_or_si128(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return _mm_and_si128(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return _mm_xor_si128(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return _mm_andnot_si128(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    typedef uint16_t bitmask_t;
+    typedef uint32_t bitmask2_t;
 
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
 
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
+    friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
 
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
+    static const int SIZE = sizeof(base<simd8<T>>::value);
 
-  /** @} */
-protected:
-  /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
-  /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
-  /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
-   *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+      return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
+    }
+  };
 
-  /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
-   *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
 
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
 
-  /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
-   *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
-   *
-   * ({"globals":{"a":{"shadowable":[}}}})
-   *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
-   *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
-   *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
-   *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
-   */
+    simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
+    simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) { return _mm_set1_epi8(_value); }
+    static simdjson_inline simd8<T> zero() { return _mm_setzero_si128(); }
+    static simdjson_inline simd8<T> load(const T values[16]) {
+      return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
+    }
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
 
+    // Store to array
+    simdjson_inline void store(T dst[16]) const { return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this); }
 
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
 
-  /**
-   * Advance to a place expecting a value (increasing depth).
-   *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
-   */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm_add_epi8(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm_sub_epi8(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return _mm_shuffle_epi8(lookup_table, *this);
+    }
 
-  simdjson_inline bool is_at_start() const noexcept;
-  /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
-   *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
-   */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
+    // get written.
+    // Design consideration: it seems like a function with the
+    // signature simd8<L> compress(uint32_t mask) would be
+    // sensible, but the AVX ISA makes this kind of approach difficult.
+    template<typename L>
+    simdjson_inline void compress(uint16_t mask, L * output) const {
+      using internal::thintable_epi8;
+      using internal::BitsSetTable256mul2;
+      using internal::pshufb_combine_table;
+      // this particular implementation was inspired by work done by @animetosho
+      // we do it in two steps, first 8 bytes and then second 8 bytes
+      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
+      uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
+      // next line just loads the 64-bit values thintable_epi8[mask1] and
+      // thintable_epi8[mask2] into a 128-bit register, using only
+      // two instructions on most compilers.
+      __m128i shufmask =  _mm_set_epi64x(thintable_epi8[mask2], thintable_epi8[mask1]);
+      // we increment by 0x08 the second half of the mask
+      shufmask =
+      _mm_add_epi8(shufmask, _mm_set_epi32(0x08080808, 0x08080808, 0, 0));
+      // this is the version "nearly pruned"
+      __m128i pruned = _mm_shuffle_epi8(*this, shufmask);
+      // we still need to put the two halves together.
+      // we compute the popcount of the first half:
+      int pop1 = BitsSetTable256mul2[mask1];
+      // then load the corresponding mask, what it does is to write
+      // only the first pop1 bytes from the first 8 bytes, and then
+      // it fills in with the bytes from the second 8 bytes + some filling
+      // at the end.
+      __m128i compactmask =
+      _mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop1 * 8));
+      __m128i answer = _mm_shuffle_epi8(pruned, compactmask);
+      _mm_storeu_si128(reinterpret_cast<__m128i *>(output), answer);
+    }
 
-  /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
-   *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
-   */
-  simdjson_inline bool is_at_key() const noexcept;
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
+    }
+  };
 
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) : simd8(_mm_setr_epi8(
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    )) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm_max_epi8(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm_min_epi8(*this, other); }
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(*this, other); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(other, *this); }
+  };
 
-  /** @copydoc error_code json_iterator::position() const noexcept; */
-  simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t* values) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) : simd8(_mm_setr_epi8(
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    )) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  friend class document;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class field;
-}; // value_iterator
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm_adds_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm_subs_epu8(*this, other); }
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm_max_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm_min_epu8(*this, other); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
 
-namespace simdjson {
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+    simdjson_inline bool is_ascii() const { return _mm_movemask_epi8(*this) == 0; }
+    simdjson_inline bool bits_not_set_anywhere() const { return _mm_testz_si128(*this, *this); }
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return _mm_testz_si128(*this, bits); }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
+    // Get one of the bits and make a bitmask out of it.
+    // e.g. value.get_bit<7>() gets the high bit
+    template<int N>
+    simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); }
+  };
 
-template<>
-struct simdjson_result<westmere::ondemand::value_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::value_iterator> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::value_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
+
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
+
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
+
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
+      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
+      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
+    }
+
+    simdjson_inline simd8<T> reduce_or() const {
+      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
+    }
+
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      this->chunks[0].compress(uint16_t(mask), output);
+      this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
+      this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
+      this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
+      return 64 - count_ones(mask);
+    }
+
+    simdjson_inline uint64_t to_bitmask() const {
+      uint64_t r0 = uint32_t(this->chunks[0].to_bitmask() );
+      uint64_t r1 =          this->chunks[1].to_bitmask() ;
+      uint64_t r2 =          this->chunks[2].to_bitmask() ;
+      uint64_t r3 =          this->chunks[3].to_bitmask() ;
+      return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
+    }
+
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] == mask,
+        this->chunks[1] == mask,
+        this->chunks[2] == mask,
+        this->chunks[3] == mask
+      ).to_bitmask();
+    }
+
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return  simd8x64<bool>(
+        this->chunks[0] == other.chunks[0],
+        this->chunks[1] == other.chunks[1],
+        this->chunks[2] == other.chunks[2],
+        this->chunks[3] == other.chunks[3]
+      ).to_bitmask();
+    }
+
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] <= mask,
+        this->chunks[1] <= mask,
+        this->chunks[2] <= mask,
+        this->chunks[3] <= mask
+      ).to_bitmask();
+    }
+  }; // struct simd8x64<T>
 
+} // namespace simd
+} // unnamed namespace
+} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for westmere */
-/* including simdjson/generic/ondemand/value.h for westmere: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+#endif // SIMDJSON_WESTMERE_SIMD_INPUT_H
+/* end file simdjson/westmere/simd.h */
+/* including simdjson/westmere/stringparsing_defs.h: #include "simdjson/westmere/stringparsing_defs.h" */
+/* begin file simdjson/westmere/stringparsing_defs.h */
+#ifndef SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
+#define SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
+
+/* including simdjson/westmere/bitmanipulation.h: #include "simdjson/westmere/bitmanipulation.h" */
+/* begin file simdjson/westmere/bitmanipulation.h */
+#ifndef SIMDJSON_WESTMERE_BITMANIPULATION_H
+#define SIMDJSON_WESTMERE_BITMANIPULATION_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/intrinsics.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <type_traits>
-
 namespace simdjson {
-
 namespace westmere {
-namespace ondemand {
-/**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
- */
-class value {
-public:
-  /**
-   * Create a new invalid value.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline value() noexcept = default;
+namespace {
 
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long ret;
+  // Search the mask data from least significant bit (LSB)
+  // to the most significant bit (MSB) for a set bit (1).
+  _BitScanForward64(&ret, input_num);
+  return (int)ret;
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO
+  return __builtin_ctzll(input_num);
+#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
+}
 
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num-1);
+}
 
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long leading_zero = 0;
+  // Search the mask data from most significant bit (MSB)
+  // to least significant bit (LSB) for a set bit (1).
+  if (_BitScanReverse64(&leading_zero, input_num))
+    return (int)(63 - leading_zero);
+  else
+    return 64;
 #else
-    noexcept
+  return __builtin_clzll(input_num);
+#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
+}
+
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
+  // note: we do not support legacy 32-bit Windows in this kernel
+  return __popcnt64(input_num);// Visual Studio wants two underscores
+}
+#else
+simdjson_inline long long int count_ones(uint64_t input_num) {
+  return _popcnt64(input_num);
+}
 #endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
+
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
+                                uint64_t *result) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  return _addcarry_u64(0, value1, value2,
+                       reinterpret_cast<unsigned __int64 *>(result));
+#else
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
 #endif
-  }
+}
 
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
+} // unnamed namespace
+} // namespace westmere
+} // namespace simdjson
 
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
+#endif // SIMDJSON_WESTMERE_BITMANIPULATION_H
+/* end file simdjson/westmere/bitmanipulation.h */
+/* including simdjson/westmere/simd.h: #include "simdjson/westmere/simd.h" */
+/* begin file simdjson/westmere/simd.h */
+#ifndef SIMDJSON_WESTMERE_SIMD_H
+#define SIMDJSON_WESTMERE_SIMD_H
 
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Cast this JSON value (inside string) to a unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+namespace simdjson {
+namespace westmere {
+namespace {
+namespace simd {
 
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  template<typename Child>
+  struct base {
+    __m128i value;
 
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+    // Zero constructor
+    simdjson_inline base() : value{__m128i()} {}
 
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
+    // Conversion from SIMD register
+    simdjson_inline base(const __m128i _value) : value(_value) {}
 
-  /**
-   * Cast this JSON value (inside string) to a double
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+    // Conversion to SIMD register
+    simdjson_inline operator const __m128i&() const { return this->value; }
+    simdjson_inline operator __m128i&() { return this->value; }
 
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return _mm_or_si128(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return _mm_and_si128(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return _mm_xor_si128(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return _mm_andnot_si128(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    typedef uint16_t bitmask_t;
+    typedef uint32_t bitmask2_t;
 
-  /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
 
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+    friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
 
-  /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+    static const int SIZE = sizeof(base<simd8<T>>::value);
 
-#if SIMDJSON_EXCEPTIONS
-  /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() noexcept(false);
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline operator double() noexcept(false);
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
-   */
-  simdjson_inline operator bool() noexcept(false);
-#endif
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+      return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
+    }
+  };
 
-  /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
-   *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
 
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
 
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
+    simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
+    simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) { return _mm_set1_epi8(_value); }
+    static simdjson_inline simd8<T> zero() { return _mm_setzero_si128(); }
+    static simdjson_inline simd8<T> load(const T values[16]) {
+      return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
+    }
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  /**
-   * Checks whether the value is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
 
-  /**
-   * Checks whether the value is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+    // Store to array
+    simdjson_inline void store(T dst[16]) const { return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this); }
 
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
 
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   *
-   * See also value::raw_json().
-   */
-  simdjson_inline std::string_view raw_json_token() noexcept;
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm_add_epi8(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm_sub_epi8(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-  /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return _mm_shuffle_epi8(lookup_table, *this);
+    }
 
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
+    // get written.
+    // Design consideration: it seems like a function with the
+    // signature simd8<L> compress(uint32_t mask) would be
+    // sensible, but the AVX ISA makes this kind of approach difficult.
+    template<typename L>
+    simdjson_inline void compress(uint16_t mask, L * output) const {
+      using internal::thintable_epi8;
+      using internal::BitsSetTable256mul2;
+      using internal::pshufb_combine_table;
+      // this particular implementation was inspired by work done by @animetosho
+      // we do it in two steps, first 8 bytes and then second 8 bytes
+      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
+      uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
+      // next line just loads the 64-bit values thintable_epi8[mask1] and
+      // thintable_epi8[mask2] into a 128-bit register, using only
+      // two instructions on most compilers.
+      __m128i shufmask =  _mm_set_epi64x(thintable_epi8[mask2], thintable_epi8[mask1]);
+      // we increment by 0x08 the second half of the mask
+      shufmask =
+      _mm_add_epi8(shufmask, _mm_set_epi32(0x08080808, 0x08080808, 0, 0));
+      // this is the version "nearly pruned"
+      __m128i pruned = _mm_shuffle_epi8(*this, shufmask);
+      // we still need to put the two halves together.
+      // we compute the popcount of the first half:
+      int pop1 = BitsSetTable256mul2[mask1];
+      // then load the corresponding mask, what it does is to write
+      // only the first pop1 bytes from the first 8 bytes, and then
+      // it fills in with the bytes from the second 8 bytes + some filling
+      // at the end.
+      __m128i compactmask =
+      _mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop1 * 8));
+      __m128i answer = _mm_shuffle_epi8(pruned, compactmask);
+      _mm_storeu_si128(reinterpret_cast<__m128i *>(output), answer);
+    }
 
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
+    }
+  };
 
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
-   *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) : simd8(_mm_setr_epi8(
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    )) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm_max_epi8(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm_min_epi8(*this, other); }
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(*this, other); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm_cmpgt_epi8(other, *this); }
+  };
 
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t* values) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) : simd8(_mm_setr_epi8(
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    )) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-protected:
-  /**
-   * Create a value.
-   */
-  simdjson_inline value(const value_iterator &iter) noexcept;
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm_adds_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm_subs_epu8(*this, other); }
 
-  /**
-   * Skip this value, allowing iteration to continue.
-   */
-  simdjson_inline void skip() noexcept;
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm_max_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm_min_epu8(*this, other); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
 
-  /**
-   * Start a value at the current position.
-   *
-   * (It should already be started; this is just a self-documentation method.)
-   */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+    simdjson_inline bool is_ascii() const { return _mm_movemask_epi8(*this) == 0; }
+    simdjson_inline bool bits_not_set_anywhere() const { return _mm_testz_si128(*this, *this); }
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return _mm_testz_si128(*this, bits); }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
+    // Get one of the bits and make a bitmask out of it.
+    // e.g. value.get_bit<7>() gets the high bit
+    template<int N>
+    simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); }
+  };
 
-  /**
-   * Resume a value.
-   */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
 
-  /**
-   * Get the object, starting or resuming it as necessary
-   */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
 
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
 
-  value_iterator iter{};
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
+      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
+      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
+    }
 
-  friend class document;
-  friend class array_iterator;
-  friend class field;
-  friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
-  friend class field;
-};
+    simdjson_inline simd8<T> reduce_or() const {
+      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
+    }
 
-} // namespace ondemand
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      this->chunks[0].compress(uint16_t(mask), output);
+      this->chunks[1].compress(uint16_t(mask >> 16), output + 16 - count_ones(mask & 0xFFFF));
+      this->chunks[2].compress(uint16_t(mask >> 32), output + 32 - count_ones(mask & 0xFFFFFFFF));
+      this->chunks[3].compress(uint16_t(mask >> 48), output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
+      return 64 - count_ones(mask);
+    }
+
+    simdjson_inline uint64_t to_bitmask() const {
+      uint64_t r0 = uint32_t(this->chunks[0].to_bitmask() );
+      uint64_t r1 =          this->chunks[1].to_bitmask() ;
+      uint64_t r2 =          this->chunks[2].to_bitmask() ;
+      uint64_t r3 =          this->chunks[3].to_bitmask() ;
+      return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
+    }
+
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] == mask,
+        this->chunks[1] == mask,
+        this->chunks[2] == mask,
+        this->chunks[3] == mask
+      ).to_bitmask();
+    }
+
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return  simd8x64<bool>(
+        this->chunks[0] == other.chunks[0],
+        this->chunks[1] == other.chunks[1],
+        this->chunks[2] == other.chunks[2],
+        this->chunks[3] == other.chunks[3]
+      ).to_bitmask();
+    }
+
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] <= mask,
+        this->chunks[1] <= mask,
+        this->chunks[2] <= mask,
+        this->chunks[3] <= mask
+      ).to_bitmask();
+    }
+  }; // struct simd8x64<T>
+
+} // namespace simd
+} // unnamed namespace
 } // namespace westmere
 } // namespace simdjson
 
+#endif // SIMDJSON_WESTMERE_SIMD_INPUT_H
+/* end file simdjson/westmere/simd.h */
+
 namespace simdjson {
+namespace westmere {
+namespace {
 
-template<>
-struct simdjson_result<westmere::ondemand::value> : public westmere::implementation_simdjson_result_base<westmere::ondemand::value> {
+using namespace simd;
+
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::value &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+  static constexpr uint32_t BYTES_PROCESSED = 32;
+  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
 
-  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() noexcept;
+  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
+  simdjson_inline bool has_backslash() { return bs_bits != 0; }
+  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
+  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
 
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  uint32_t bs_bits;
+  uint32_t quote_bits;
+}; // struct backslash_and_quote
 
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 31 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v0(src);
+  simd8<uint8_t> v1(src + 16);
+  v0.store(dst);
+  v1.store(dst + 16);
+  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
+  return {
+    uint32_t(bs_and_quote),      // bs_bits
+    uint32_t(bs_and_quote >> 32) // quote_bits
+  };
+}
 
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+} // unnamed namespace
+} // namespace westmere
+} // namespace simdjson
 
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator westmere::ondemand::array() noexcept(false);
-  simdjson_inline operator westmere::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
+#endif // SIMDJSON_WESTMERE_STRINGPARSING_DEFS_H
+/* end file simdjson/westmere/stringparsing_defs.h */
+/* end file simdjson/westmere/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for westmere: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for westmere */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
 
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) noexcept;
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for westmere: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<westmere::ondemand::value> operator[](int) noexcept = delete;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Get the type of this JSON value.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   */
-  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
+namespace simdjson {
+namespace westmere {
+/**
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
+ */
+namespace ondemand {
 
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
+/** @copydoc simdjson::westmere::number_type */
+using number_type = simdjson::westmere::number_type;
+
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
+
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
 
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for westmere */
-/* including simdjson/generic/ondemand/logger.h for westmere: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for westmere */
+/* including simdjson/generic/ondemand/deserialize.h for westmere: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for westmere */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <concepts>
 namespace simdjson {
-namespace westmere {
-namespace ondemand {
 
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
+namespace tag_invoke_fn_ns {
+void tag_invoke();
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
 };
+} // namespace tag_invoke_fn_ns
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
-#endif
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
 
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
 
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
 
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<westmere::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = westmere::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = westmere::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = westmere::ondemand::value;
+  using document_type = westmere::ondemand::document;
+  using document_reference_type = westmere::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
+
+
+} deserialize{};
 
-} // namespace logger
-} // namespace ondemand
-} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for westmere */
-/* including simdjson/generic/ondemand/token_iterator.h for westmere: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for westmere */
+/* including simdjson/generic/ondemand/value_iterator.h for westmere: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -92472,635 +92723,467 @@ namespace westmere {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
  *
  * @private This is not intended for external use.
  */
-class token_iterator {
-public:
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
   /**
-   * Create a new invalid token_iterator.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
+   * The starting token index for this value
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  token_position _start_position{};
+
+public:
+  simdjson_inline value_iterator() noexcept = default;
 
   /**
-   * Advance to the next token (returning the current one).
+   * Denote that we're starting a document.
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  simdjson_inline void start_document() noexcept;
+
   /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   *
+   * Optimized for scalars.
    */
-  simdjson_inline uint32_t current_offset() const noexcept;
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
+
   /**
-   * Get the JSON text for a given token (relative).
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
-   *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
+   * Tell whether the iterator is at the EOF mark
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
-   *
-   * The length will include any whitespace at the end of the token.
-   *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * Tell whether the iterator is at the start of the value
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline bool at_start() const noexcept;
 
   /**
-   * Get the JSON text for a given token.
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param position The position of the token.
-   *
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_inline bool is_open() const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
-   *
-   * The length will include any whitespace at the end of the token.
-   *
-   * @param position The position of the token.
+   * Tell whether the value is at an object's first field (just after the {).
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_inline bool at_first_field() const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a root token.
-   *
-   * The length will include any whitespace at the end of the token.
-   *
-   * @param position The position of the token (start of the document).
+   * Abandon all iteration.
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_inline void abandon() noexcept;
+
   /**
-   * Return the current index.
+   * Get the child value as a value_iterator.
    */
-  simdjson_inline token_position position() const noexcept;
+  simdjson_inline value_iterator child_value() const noexcept;
+
   /**
-   * Reset to a previously saved index.
+   * Get the depth of this value.
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
-
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
-
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
-
-protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+  simdjson_inline int32_t depth() const noexcept;
 
   /**
-   * Get the index of the JSON text for a given token (relative).
-   *
-   * This is not null-terminated; it is a view into the JSON.
+   * Get the JSON type of this value.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
+
   /**
-   * Get the index of the JSON text for a given token.
-   *
-   * This is not null-terminated; it is a view into the JSON.
+   * @addtogroup object Object iteration
    *
-   * @param position The position of the token.
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
    *
+   * @{
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
-
-  const uint8_t *buf{};
-  token_position _position{};
-
-  friend class json_iterator;
-  friend class value_iterator;
-  friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-};
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<westmere::ondemand::token_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::token_iterator> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::token_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for westmere */
-/* including simdjson/generic/ondemand/json_iterator.h for westmere: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-/**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
- *
- * @private This is not intended for external use.
- */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
   /**
-   * Next free location in the string buffer.
+   * Start an object iteration.
    *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
    */
-  uint8_t *_string_buf_loc{};
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
   /**
-   * JSON error, if there is one.
-   *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
+   * Start an object iteration from the root.
    *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
    */
-  error_code error{SUCCESS};
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
   /**
-   * Depth of the current token in the JSON.
+   * Checks whether an object could be started from the root. May be called by start_root_object.
    *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
-   */
-  bool _streaming{false};
-
-public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
-
-  /**
-   * Tell whether the iterator is still at the start
-   */
-  simdjson_inline bool at_root() const noexcept;
-
-  /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
-   */
-  simdjson_inline bool streaming() const noexcept;
-
-  /**
-   * Get the root value iterator
-   */
-  simdjson_inline token_position root_position() const noexcept;
-  /**
-   * Assert that we are at the document depth (== 1)
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
    */
-  simdjson_inline void assert_at_document_depth() const noexcept;
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
   /**
-   * Assert that we are at the root of the document
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
    */
-  simdjson_inline void assert_at_root() const noexcept;
-
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
   /**
-   * Tell whether the iterator is at the EOF mark
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
    */
-  simdjson_inline bool at_end() const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
   /**
-   * Tell whether the iterator is live (has not been moved).
+   * Moves to the next field in an object.
+   *
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
    */
-  simdjson_inline bool is_alive() const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
 
   /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   * Get the current field's key.
    */
-  simdjson_inline void abandon() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
 
   /**
-   * Advance the current token without modifying depth.
+   * Pass the : in the field and move to its value.
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
 
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Find the next field with the given key.
    *
-   * @return whether there is a single token
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline bool is_single_token() const noexcept;
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
 
   /**
-   * Assert that there are at least the given number of tokens left.
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
-  /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * Assumes you have called next_field() or otherwise matched the previous value.
    *
-   * Has no effect in release builds.
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
+
   /**
-   * Get the JSON text for a given token (relative).
+   * Find the field with the given key without regard to order, and *without* unescaping.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Assumes you have called next_field() or otherwise matched the previous value.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * This means the iterator must be sitting at the next key:
    *
-   * The length will include any whitespace at the end of the token.
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
+
+  /** @} */
+
   /**
-   * Get a pointer to the current location in the input buffer.
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
    */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
+
   /**
-   * Get the JSON text for a given token.
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param position The position of the token to retrieve.
+   * Check for an opening [ and start an array iteration.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
-   *
-   * The length will include any whitespace at the end of the token.
+   * Check for an opening [ and start an array iteration while at the root.
    *
-   * @param position The position of the token to retrieve.
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
   /**
-   * Get the maximum length of the JSON text for the current root token.
-   *
-   * The length will include any whitespace at the end of the token.
+   * Checks whether an array could be started from the root. May be called by start_root_array.
    *
-   * @param position The position of the token to retrieve.
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
   /**
-   * Get the JSON text for the last token in the document.
+   * Start an array iteration, after the user has already checked and moved past the [.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Does not move the iterator unless the array is empty ([]).
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
    */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
-
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
   /**
-   * Ascend one level.
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
    *
-   * Validates that the depth - 1 == parent_depth.
+   * Does not move the iterator unless the array is empty ([]).
    *
-   * @param parent_depth the expected parent depth.
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
    */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
   /**
-   * Descend one level.
+   * Moves to the next element in an array.
    *
-   * Validates that the new depth == child_depth.
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
    *
-   * @param child_depth the expected child depth.
-   */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
-
-  /**
-   * Get current depth.
-   */
-  simdjson_inline depth_t depth() const noexcept;
-
-  /**
-   * Get current (writeable) location in the string buffer.
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
    */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
   /**
-   * Report an unrecoverable error, preventing further iteration.
-   *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * Get a child value iterator.
    */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
 
-  /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
+  /** @} */
 
   /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
    */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
 
-  simdjson_inline token_position position() const noexcept;
-  /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
 
-  simdjson_inline error_code consume_character(char c) noexcept;
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
-#endif
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
 
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
+  /** @} */
+protected:
   /**
-   * Returns the current location in the document if in bounds.
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
   /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
    */
-  inline void rewind() noexcept;
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
   /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
-   */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
-
-  friend class document;
-  friend class document_stream;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<westmere::ondemand::json_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::json_iterator> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::json_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
-  simdjson_inline simdjson_result() noexcept = default;
-};
+  /**
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
+   *
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
 
-} // namespace simdjson
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for westmere */
-/* including simdjson/generic/ondemand/json_type.h for westmere: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
+   *
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   */
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
 
-/**
- * The type of a JSON value.
- */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
 
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
- */
-struct number {
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
 
   /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+   * Advance to a place expecting a value (increasing depth).
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
-   */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
-   */
-  simdjson_inline bool is_uint64() const noexcept;
-  /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
-   */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
-   */
-  simdjson_inline bool is_int64() const noexcept;
-  /**
-   * return the value as a int64_t, only valid if is_int64() is true.
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
    */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
 
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
 
+  simdjson_inline bool is_at_start() const noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
-   */
-  simdjson_inline bool is_double() const noexcept;
-  /**
-   * return the value as a double, only valid if is_double() is true.
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
+   *
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
    */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
+  simdjson_inline bool is_at_iterator_start() const noexcept;
 
   /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
+   *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
    */
-  simdjson_inline double as_double() const noexcept;
-
+  simdjson_inline bool is_at_key() const noexcept;
 
-protected:
-  /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
-   */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
-  /**
-   * End of friend declarations.
-   */
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-  /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
-   */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
 
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
+  friend class document;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
 } // namespace ondemand
 } // namespace westmere
@@ -93109,721 +93192,647 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &t
 namespace simdjson {
 
 template<>
-struct simdjson_result<westmere::ondemand::json_type> : public westmere::implementation_simdjson_result_base<westmere::ondemand::json_type> {
+struct simdjson_result<westmere::ondemand::value_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::value_iterator> {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(westmere::ondemand::value_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for westmere */
-/* including simdjson/generic/ondemand/raw_json_string.h for westmere: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for westmere */
+/* including simdjson/generic/ondemand/value.h for westmere: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace westmere {
 namespace ondemand {
-
 /**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
- *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
- *
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
  */
-class raw_json_string {
+class value {
 public:
   /**
-   * Create a new invalid raw_json_string.
+   * Create a new invalid value.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline raw_json_string() noexcept = default;
+  simdjson_inline value() noexcept = default;
 
   /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
+   * Get this value as the given type.
    *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * It *must* be terminated by a ", and be a valid JSON string.
-   */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
-  /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
    *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  simdjson_inline const char * raw() const noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
+   * Get this value as the given type.
    *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
-   *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
-   *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Cast this JSON value to an array.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
-   *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Cast this JSON value to an object.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
-
-private:
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
   /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * Checks whether the inner pointer is non-null and thus usable.
+   * Cast this JSON value (inside string) to a double
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
+   * Cast this JSON value to a string.
    *
-   * ## IMPORTANT: string_view lifetime
+   * The string is guaranteed to be valid UTF-8.
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * Equivalent to get<std::string_view>().
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
-   *
-   * ## IMPORTANT: string_view lifetime
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
-};
-
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
-
-/**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
- */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
-
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<westmere::ondemand::raw_json_string> : public westmere::implementation_simdjson_result_base<westmere::ondemand::raw_json_string> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for westmere */
-/* including simdjson/generic/ondemand/parser.h for westmere: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <memory>
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-/**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
- *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
-
-/**
- * A JSON fragment iterator.
- *
- * This holds the actual iterator as well as the buffer for writing strings.
- */
-class parser {
-public:
-  /**
-   * Create a JSON parser.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * The new parser will have zero capacity.
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
-
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
-
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
 
   /**
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
-   *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
-   *
-   * ### IMPORTANT: Validate what you use
-   *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
-   *
-   * ### IMPORTANT: Document Lifetime
+   * Cast this JSON value to a "wobbly" string.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
    *
-   * ### REQUIRED: Buffer Padding
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * ### std::string references
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+
+  /**
+   * Cast this JSON value to a bool.
    *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+
+  /**
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
    *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @returns An instance of type T
    */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
-
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
   /**
-   * @private
+   * Cast this JSON value to an array.
    *
-   * Start iterating an on-demand JSON document.
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
    *
-   * ### IMPORTANT: Buffer Lifetime
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
    *
-   * ### IMPORTANT: Document Lifetime
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   * Equivalent to get<std::string_view>().
    *
-   * ### REQUIRED: Buffer Padding
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * @param json The JSON to parse.
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
    *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
-
+  simdjson_inline operator bool() noexcept(false);
+#endif
 
   /**
-   * Parse a buffer containing many JSON documents.
-   *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
+   * Begin array iteration.
    *
-   * No copy of the input buffer is made.
+   * Part of the std::iterable interface.
    *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
    *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * ### Format
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
    *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
    *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * ### REQUIRED: Buffer Padding
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
+
+  /**
+   * Look up a field by name on an object, without regard to key order.
    *
-   * ### Threads
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * ### Parser Capacity
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
    *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
   /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  /**
+   * Checks whether the value is a string.
    *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
-  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * Checks whether the value is a negative number.
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{true};
-  #else
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
    *
-   * ## IMPORTANT: string_view lifetime
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * @returns the type of the number
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
    *
-   * ## IMPORTANT: string_view lifetime
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
-   */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
-
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
-
-  friend class json_iterator;
-  friend class document_stream;
-};
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<westmere::ondemand::parser> : public westmere::implementation_simdjson_result_base<westmere::ondemand::parser> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::parser &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for westmere */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for westmere: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-/**
- * A forward-only JSON array.
- */
-class array {
-public:
-  /**
-   * Create a new invalid array.
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
    */
-  simdjson_inline array() noexcept = default;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
   /**
-   * Begin array iteration.
+   * Get the raw JSON for this token.
    *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
-  /**
-   * Sentinel representing the end of the array.
+   * The string_view will always point into the input buffer.
    *
-   * Part of the std::iterable interface.
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
    */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  simdjson_inline std::string_view raw_json_token() noexcept;
+
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
   /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Returns the current location in the document if in bounds.
    */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   * Returns the current depth in the document if in bounds.
    *
-   * @returns true if the array contains some elements (not empty)
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+
   /**
    * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
    *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
    *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
    *
    * Note that at_pointer() called on the document automatically calls the document's rewind
    * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
    *
    * You may only call at_pointer on an array after it has been created, but before it has
    * been first accessed. When calling at_pointer on an array, the pointer is advanced to
    * the location indicated by the JSON pointer (in case of success). It is no longer possible
    * to call at_pointer on the same array.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
@@ -93831,91 +93840,62 @@ class array {
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
    * JSONPath queries that trivially convertible to JSON Pointer queries: key
    * names and array indices.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+
 
-  /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
 protected:
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * Create a value.
    */
-  simdjson_inline error_code consume() noexcept;
+  simdjson_inline value(const value_iterator &iter) noexcept;
 
   /**
-   * Begin array iteration.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
-  /**
-   * Begin array iteration from the root.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   * Skip this value, allowing iteration to continue.
    */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  simdjson_inline void skip() noexcept;
+
   /**
-   * Begin array iteration.
-   *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
+   * Start a value at the current position.
    *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   * (It should already be started; this is just a self-documentation method.)
    */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
 
   /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
-   *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
+   * Resume a value.
    */
-  simdjson_inline array(const value_iterator &iter) noexcept;
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
 
   /**
-   * Iterator marking current position.
-   *
-   * iter.is_alive() == false indicates iteration is complete.
+   * Get the object, starting or resuming it as necessary
    */
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
+
   value_iterator iter{};
 
-  friend class value;
   friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
   friend class array_iterator;
+  friend class field;
+  friend class object;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
+  friend class field;
 };
 
 } // namespace ondemand
@@ -93925,1596 +93905,1046 @@ class array {
 namespace simdjson {
 
 template<>
-struct simdjson_result<westmere::ondemand::array> : public westmere::implementation_simdjson_result_base<westmere::ondemand::array> {
+struct simdjson_result<westmere::ondemand::value> : public westmere::implementation_simdjson_result_base<westmere::ondemand::value> {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::array &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(westmere::ondemand::value &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
 
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for westmere */
-/* including simdjson/generic/ondemand/array_iterator.h for westmere: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() noexcept;
 
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
 
-/**
- * A forward-only JSON array.
- *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
- */
-class array_iterator {
-public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
 
-  //
-  // Iterator interface
-  //
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator westmere::ondemand::array() noexcept(false);
+  simdjson_inline operator westmere::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
 
   /**
-   * Get the current element.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * Part of the std::iterator interface.
-   */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  /**
-   * Check if we are at the end of the JSON.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * Part of the std::iterator interface.
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
    *
-   * @return true if there are no more elements in the JSON array.
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) noexcept;
+
   /**
-   * Check if there are more elements in the JSON array.
+   * Look up a field by name on an object, without regard to key order.
    *
-   * Part of the std::iterator interface.
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * @return true if there are more elements in the JSON array.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) noexcept = delete;
+
   /**
-   * Move to the next element.
+   * Get the type of this JSON value.
    *
-   * Part of the std::iterator interface.
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
    */
-  simdjson_inline array_iterator &operator++() noexcept;
-
-private:
-  value_iterator iter{};
+  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
 
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-  friend class array;
-  friend class value;
-  friend struct simdjson_result<array_iterator>;
-};
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
 
-} // namespace ondemand
-} // namespace westmere
 } // namespace simdjson
 
-namespace simdjson {
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for westmere */
+/* including simdjson/generic/ondemand/logger.h for westmere: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
 
-template<>
-struct simdjson_result<westmere::ondemand::array_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::array_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  //
-  // Iterator interface
-  //
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<westmere::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<westmere::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &operator++() noexcept;
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
+
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
 };
 
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
+#else
+  static constexpr const bool LOG_ENABLED = false;
+#endif
+
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+} // namespace logger
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for westmere */
-/* including simdjson/generic/ondemand/document.h for westmere: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for westmere */
+/* including simdjson/generic/ondemand/token_iterator.h for westmere: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
- *
- * Used by tokens to get text, and string buffer location.
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
  *
- * You must keep the document around during iteration.
+ * @private This is not intended for external use.
  */
-class document {
+class token_iterator {
 public:
   /**
-   * Create a new invalid document.
+   * Create a new invalid token_iterator.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
 
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   * Advance to the next token (returning the current one).
    */
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * Reports the current offset in bytes from the start of the underlying buffer.
    */
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline uint32_t current_offset() const noexcept;
   /**
-   * Cast this JSON value to an unsigned integer.
+   * Get the JSON text for a given token (relative).
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Cast this JSON value (inside string) to an unsigned integer.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+
   /**
-   * Cast this JSON value to a signed integer.
+   * Get the JSON text for a given token.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Cast this JSON value (inside string) to a signed integer.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Cast this JSON value to a double.
+   * Get the maximum length of the JSON text for a root token.
    *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token (start of the document).
    */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * Return the current index.
    */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline token_position position() const noexcept;
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * Reset to a previously saved index.
+   */
+  simdjson_inline void set_position(token_position target_position) noexcept;
+
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
+
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+
+protected:
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+
+  /**
+   * Get the index of the JSON text for a given token (relative).
    *
-   * Important: Calling get_string() twice on the same document is an error.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
   /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * Get the index of the JSON text for a given token.
    *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
+   * @param position The position of the token.
    *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+
+  const uint8_t *buf{};
+  token_position _position{};
+
+  friend class json_iterator;
+  friend class value_iterator;
+  friend class object;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+};
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::token_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::token_iterator> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for westmere */
+/* including simdjson/generic/ondemand/json_iterator.h for westmere: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+/**
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
+ */
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   * Next free location in the string buffer.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
    */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  uint8_t *_string_buf_loc{};
   /**
-   * Cast this JSON value to a raw_json_string.
+   * JSON error, if there is one.
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
    */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  error_code error{SUCCESS};
   /**
-   * Cast this JSON value to a bool.
+   * Depth of the current token in the JSON.
    *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
    */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  depth_t _depth{};
   /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
    */
-  simdjson_inline simdjson_result<value> get_value() noexcept;
+  token_position _root{};
+  /**
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
+   */
+  bool _streaming{false};
 
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   * Skips a JSON value, whether it is a scalar, array or object.
    */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   * Tell whether the iterator is still at the start
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
+  simdjson_inline bool at_root() const noexcept;
+
   /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
    */
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+  simdjson_inline bool streaming() const noexcept;
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * Get the root value iterator
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline token_position root_position() const noexcept;
+  /**
+   * Assert that we are at the document depth (== 1)
+   */
+  simdjson_inline void assert_at_document_depth() const noexcept;
+  /**
+   * Assert that we are at the root of the document
+   */
+  simdjson_inline void assert_at_root() const noexcept;
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
+   * Tell whether the iterator is at the EOF mark
    */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
-  template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
+  simdjson_inline bool at_end() const noexcept;
 
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   * Tell whether the iterator is live (has not been moved).
    */
-  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline bool is_alive() const noexcept;
+
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
    */
-  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline void abandon() noexcept;
+
   /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * Advance the current token without modifying depth.
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+
   /**
-   * Cast this JSON value to a signed integer.
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   * @return whether there is a single token
    */
-  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline bool is_single_token() const noexcept;
+
   /**
-   * Cast this JSON value to a double.
+   * Assert that there are at least the given number of tokens left.
    *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * Has no effect in release builds.
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * Assert that the given position addresses an actual token (is within bounds).
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * Has no effect in release builds.
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
   /**
-   * Cast this JSON value to a raw_json_string.
+   * Get the JSON text for a given token (relative).
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Cast this JSON value to a value when the document is an object or an array.
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
+   * The length will include any whitespace at the end of the token.
    *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_inline operator value() noexcept(false);
-#endif
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Get a pointer to the current location in the input buffer.
    *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
   /**
-   * Begin array iteration.
+   * Get the JSON text for a given token.
    *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Part of the std::iterable interface.
+   * @param position The position of the token to retrieve.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
-   * is an error.
+   * The length will include any whitespace at the end of the token.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * Get the maximum length of the JSON text for the current root token.
    *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
+   * The length will include any whitespace at the end of the token.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * Get the JSON text for the last token in the document.
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   * Ascend one level.
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
+   * Validates that the depth - 1 == parent_depth.
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @param parent_depth the expected parent depth.
    */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
 
   /**
-   * Checks whether the document is a negative number.
+   * Descend one level.
    *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
+   * Validates that the new depth == child_depth.
    *
-   * @returns true if the number if negative.
+   * @param child_depth the expected child depth.
    */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+
   /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
+   * Get current depth.
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline depth_t depth() const noexcept;
 
   /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
+   * Get current (writeable) location in the string buffer.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
   /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
   /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  inline bool is_alive() noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
 
   /**
-   * Returns the current location in the document if in bounds.
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
 
+  simdjson_inline token_position position() const noexcept;
   /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
    */
-  inline bool at_end() const noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
 
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
 
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
-   */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
+
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   * Returns the current location in the document if in bounds.
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  inline simdjson_result<const char *> current_location() const noexcept;
 
   /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-protected:
+  inline void rewind() noexcept;
   /**
-   * Consumes the document.
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
    */
-  simdjson_inline error_code consume() noexcept;
-
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
-
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
+  simdjson_inline token_position last_position() const noexcept;
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
+  simdjson_inline token_position end_position() const noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
 
-  friend class array_iterator;
-  friend class value;
-  friend class ondemand::parser;
+  friend class document;
+  friend class document_stream;
   friend class object;
   friend class array;
+  friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
   friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::json_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::json_iterator> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::json_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+
+  simdjson_inline simdjson_result() noexcept = default;
 };
 
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for westmere */
+/* including simdjson/generic/ondemand/json_type.h for westmere: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
 /**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
+ * The type of a JSON value.
  */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
 
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
+   */
+  simdjson_inline bool is_uint64() const noexcept;
+  /**
+   * return the value as a uint64_t, only valid if is_uint64() is true.
+   */
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
 
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
+   */
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-private:
-  document *doc{nullptr};
-};
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
+   */
+  simdjson_inline bool is_double() const noexcept;
+  /**
+   * return the value as a double, only valid if is_double() is true.
+   */
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
-namespace simdjson {
+  /**
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
+   */
+  simdjson_inline double as_double() const noexcept;
 
-template<>
-struct simdjson_result<westmere::ondemand::document> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::document &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
 
-  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+protected:
+  /**
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
+   */
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
+  /**
+   * End of friend declarations.
+   */
 
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+  /**
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
+   */
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
+};
+
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
 
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
-  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator westmere::ondemand::value() noexcept(false);
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool at_end() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
-
 
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
-
-
 namespace simdjson {
 
 template<>
-struct simdjson_result<westmere::ondemand::document_reference> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document_reference> {
+struct simdjson_result<westmere::ondemand::json_type> : public westmere::implementation_simdjson_result_base<westmere::ondemand::json_type> {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result(westmere::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
-  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator westmere::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-/* end file simdjson/generic/ondemand/document.h for westmere */
-/* including simdjson/generic/ondemand/document_stream.h for westmere: #include "simdjson/generic/ondemand/document_stream.h" */
-/* begin file simdjson/generic/ondemand/document_stream.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for westmere */
+/* including simdjson/generic/ondemand/raw_json_string.h for westmere: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
-
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-/** @private Custom worker class **/
-struct stage1_worker {
-  stage1_worker() noexcept = default;
-  stage1_worker(const stage1_worker&) = delete;
-  stage1_worker(stage1_worker&&) = delete;
-  stage1_worker operator=(const stage1_worker&) = delete;
-  ~stage1_worker();
-  /**
-   * We only start the thread when it is needed, not at object construction, this may throw.
-   * You should only call this once.
-   **/
-  void start_thread();
-  /**
-   * Start a stage 1 job. You should first call 'run', then 'finish'.
-   * You must call start_thread once before.
-   */
-  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
-  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
-  void finish();
-
-private:
-
-  /**
-   * Normally, we would never stop the thread. But we do in the destructor.
-   * This function is only safe assuming that you are not waiting for results. You
-   * should have called run, then finish, and be done.
-   **/
-  void stop_thread();
-
-  std::thread thread{};
-  /** These three variables define the work done by the thread. **/
-  ondemand::parser * stage1_thread_parser{};
-  size_t _next_batch_start{};
-  document_stream * owner{};
-  /**
-   * We have two state variables. This could be streamlined to one variable in the future but
-   * we use two for clarity.
-   */
-  bool has_work{false};
-  bool can_work{true};
-
-  /**
-   * We lock using a mutex.
-   */
-  std::mutex locking_mutex{};
-  std::condition_variable cond_var{};
-
-  friend class document_stream;
-};
-#endif  // SIMDJSON_THREADS_ENABLED
-
 /**
- * A forward-only stream of documents.
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
  *
- * Produced by parser::iterate_many.
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
+ *
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
  *
  */
-class document_stream {
+class raw_json_string {
 public:
   /**
-   * Construct an uninitialized document_stream.
+   * Create a new invalid raw_json_string.
    *
-   *  ```c++
-   *  document_stream docs;
-   *  auto error = parser.iterate_many(json).get(docs);
-   *  ```
-   */
-  simdjson_inline document_stream() noexcept;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream(document_stream &&other) noexcept = default;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
-
-  simdjson_inline ~document_stream() noexcept;
-
-  /**
-   * Returns the input size in bytes.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  inline size_t size_in_bytes() const noexcept;
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * After iterating through the stream, this method
-   * returns the number of bytes that were not parsed at the end
-   * of the stream. If truncated_bytes() differs from zero,
-   * then the input was truncated maybe because incomplete JSON
-   * documents were found at the end of the stream. You
-   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * You should only call truncated_bytes() after streaming through all
-   * documents, like so:
+   * The given location must be just *after* the beginning quote (") in the JSON file.
    *
-   *   document_stream stream = parser.iterate_many(json,window);
-   *   for(auto & doc : stream) {
-   *      // do something with doc
-   *   }
-   *   size_t truncated = stream.truncated_bytes();
+   * It *must* be terminated by a ", and be a valid JSON string.
+   */
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  /**
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
    */
-  inline size_t truncated_bytes() const noexcept;
-
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
-
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
-
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
-
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
-
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
-
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
+  simdjson_inline const char * raw() const noexcept;
 
   /**
-   * Start iterating the documents in the stream.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
+   *
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
+   *
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline iterator begin() noexcept;
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
+
   /**
-   * The end of the stream, for iterator comparison purposes.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   *
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
+   *
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
+   *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline iterator end() noexcept;
-
-private:
-
-  document_stream &operator=(const document_stream &) = delete; // Disallow copying
-  document_stream(const document_stream &other) = delete; // Disallow copying
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
 
   /**
-   * Construct a document_stream. Does not allocate or parse anything until the iterator is
-   * used.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * @param parser is a reference to the parser instance used to generate this document_stream
-   * @param buf is the raw byte buffer we need to process
-   * @param len is the length of the raw byte buffer in bytes
-   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
+   *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline document_stream(
-    ondemand::parser &parser,
-    const uint8_t *buf,
-    size_t len,
-    size_t batch_size,
-    bool allow_comma_separated
-  ) noexcept;
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
 
   /**
-   * Parse the first document in the buffer. Used by begin(), to handle allocation and
-   * initialization.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  inline void start() noexcept;
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
 
   /**
-   * Parse the next document found in the buffer previously given to document_stream.
-   *
-   * The content should be a valid JSON document encoded as UTF-8. If there is a
-   * UTF-8 BOM, the parser skips it.
-   *
-   * You do NOT need to pre-allocate a parser.  This function takes care of
-   * pre-allocating a capacity defined by the batch_size defined when creating the
-   * document_stream object.
-   *
-   * The function returns simdjson::EMPTY if there is no more data to be parsed.
-   *
-   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
-   * and indicates that the buffer has successfully been parsed to the end.
-   * Every document it contained has been parsed without error.
-   *
-   * The function returns an error code from simdjson/simdjson.h in case of failure
-   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
-   * the simdjson::error_message function converts these error codes into a string).
-   *
-   * You can also check validity by calling parser.is_valid(). The same parser can
-   * and should be reused for the other documents in the buffer.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  inline void next() noexcept;
-
-  /** Move the json_iterator of the document to the location of the next document in the stream. */
-  inline void next_document() noexcept;
-
-  /** Get the next document index. */
-  inline size_t next_batch_start() const noexcept;
-
-  /** Pass the next batch through stage 1 with the given parser. */
-  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+  simdjson_inline bool is_equal(const char* target) const noexcept;
 
-  // Fields
-  ondemand::parser *parser;
-  const uint8_t *buf;
-  size_t len;
-  size_t batch_size;
-  bool allow_comma_separated;
   /**
-   * We are going to use just one document instance. The document owns
-   * the json_iterator. It implies that we only ever pass a reference
-   * to the document to the users.
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
    */
-  document doc{};
-  /** The error (or lack thereof) from the current document. */
-  error_code error;
-  size_t batch_start{0};
-  size_t doc_index{};
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
-  bool use_thread;
-
-  inline void load_from_stage1_thread() noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
 
-  /** Start a thread to run stage 1 on the next batch. */
-  inline void start_stage1_thread() noexcept;
+private:
 
-  /** Wait for the stage 1 thread to finish and capture the results. */
-  inline void finish_stage1_thread() noexcept;
 
-  /** The error returned from the stage 1 thread. */
-  error_code stage1_thread_error{UNINITIALIZED};
-  /** The thread used to run stage 1 against the next batch in the background. */
-  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
   /**
-   * The parser used to run stage 1 in the background. Will be swapped
-   * with the regular parser when finished.
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
    */
-  ondemand::parser stage1_thread_parser{};
-
-  friend struct stage1_worker;
-  #endif // SIMDJSON_THREADS_ENABLED
-
-  friend class parser;
-  friend class document;
-  friend class json_iterator;
-  friend struct simdjson_result<ondemand::document_stream>;
-  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
-};  // document_stream
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-template<>
-struct simdjson_result<westmere::ondemand::document_stream> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document_stream> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::document_stream &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
-/* end file simdjson/generic/ondemand/document_stream.h for westmere */
-/* including simdjson/generic/ondemand/field.h for westmere: #include "simdjson/generic/ondemand/field.h" */
-/* begin file simdjson/generic/ondemand/field.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  simdjson_inline void consume() noexcept { buf = nullptr; }
 
-/**
- * A JSON field (key/value pair) in an object.
- *
- * Returned from object iteration.
- *
- * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
- */
-class field : public std::pair<raw_json_string, value> {
-public:
   /**
-   * Create a new invalid field.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
+   * Checks whether the inner pointer is non-null and thus usable.
    */
-  simdjson_inline field() noexcept;
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
 
   /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it. The content is stored in the receiver.
+   * ## IMPORTANT: string_view lifetime
    *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  template <typename string_type>
-  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a raw_json_string. Can be used for direct comparison with
-   * an unescaped C string: e.g., key() == "test". This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key() for a similar function which returns
-   * a more convenient std::string_view result.
-   */
-  simdjson_inline raw_json_string key() const noexcept;
-  /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
-   */
-  simdjson_inline std::string_view key_raw_json_token() const noexcept;
-  /**
-   * Get the key as a string_view. This does not include the quotes and
-   * the string is unprocessed key so it may contain escape characters
-   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
-   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
-   */
-  simdjson_inline std::string_view escaped_key() const noexcept;
-  /**
-   * Get the field value.
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline ondemand::value &value() & noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+
   /**
-   * @overload ondemand::value &ondemand::value() & noexcept
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline ondemand::value value() && noexcept;
-
-protected:
-  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
-  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
-  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
-  friend struct simdjson_result<field>;
-  friend class object_iterator;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
+  friend class object;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
 };
 
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+
+
 } // namespace ondemand
 } // namespace westmere
 } // namespace simdjson
@@ -95522,249 +94952,397 @@ class field : public std::pair<raw_json_string, value> {
 namespace simdjson {
 
 template<>
-struct simdjson_result<westmere::ondemand::field> : public westmere::implementation_simdjson_result_base<westmere::ondemand::field> {
+struct simdjson_result<westmere::ondemand::raw_json_string> : public westmere::implementation_simdjson_result_base<westmere::ondemand::raw_json_string> {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::field &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 
-  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  template<typename string_type>
-  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> key() noexcept;
-  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> value() noexcept;
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-/* end file simdjson/generic/ondemand/field.h for westmere */
-/* including simdjson/generic/ondemand/object.h for westmere: #include "simdjson/generic/ondemand/object.h" */
-/* begin file simdjson/generic/ondemand/object.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for westmere */
+/* including simdjson/generic/ondemand/parser.h for westmere: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
 /**
- * A forward-only JSON object field iterator.
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
  */
-class object {
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
+ *
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
+ */
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
 public:
   /**
-   * Create a new invalid object.
+   * Create a JSON parser.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * The new parser will have zero capacity.
    */
-  simdjson_inline object() noexcept = default;
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
-  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<object_iterator> end() noexcept;
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+   * Start iterating an on-demand JSON document.
    *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
    *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
    *
-   * You are expected to access keys only once. You should access the value corresponding to a
-   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
+   * ### IMPORTANT: Validate what you use
    *
-   * If you expect to have keys with escape characters, please review our documentation.
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * ### IMPORTANT: Document Lifetime
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+   * ### REQUIRED: Buffer Padding
    *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
+   * ### std::string references
    *
-   * If you expect to have keys with escape characters, please review our documentation.
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
 
   /**
-   * Get the value associated with the given JSON pointer. We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * @private
+   *
+   * Start iterating an on-demand JSON document.
    *
    *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
+   *   json_iterator doc = parser.iterate(json);
    *
-   * It is allowed for a key to be the empty string:
+   * ### IMPORTANT: Buffer Lifetime
    *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
-   * instance: there is no rewind and no invalidation.
+   * ### IMPORTANT: Document Lifetime
    *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * @param json The JSON to parse.
+   *
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * Parse a buffer containing many JSON documents.
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
+   *
+   * No copy of the input buffer is made.
+   *
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   *
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
+   *
+   * ### Format
+   *
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
+   *
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
+   *
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
+   *
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * ### Threads
+   *
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
+   *
+   * ### Parser Capacity
+   *
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
+   *
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
    */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
 
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the object. You should still consume values only once even if you
-   * can iterate through the object more than once. If you unescape a string or a key
-   * within the object more than once, you have unsafe code. Note that rewinding an object
-   * means that you may need to reparse it anew: it is not a free operation.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   */
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+
+  /**
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
    *
-   * @returns true if the object contains some elements (not empty)
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   *
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * This method scans the beginning of the object and checks whether the
-   * object is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  inline simdjson_result<bool> is_empty() & noexcept;
+  bool threaded{true};
+  #else
   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
+  #endif
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
+
   /**
-   * Consumes the object and returns a string_view instance corresponding to the
-   * object as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   *
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
 
-protected:
+#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Go to the end of the object, no matter where you are right now.
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
    */
-  simdjson_inline error_code consume() noexcept;
-  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
-  static simdjson_inline object resume(const value_iterator &iter) noexcept;
-  simdjson_inline object(const value_iterator &iter) noexcept;
-
-  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
+#endif
 
-  value_iterator iter{};
+private:
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  std::unique_ptr<token_position[]> start_positions{};
+#endif
 
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<object>;
+  friend class json_iterator;
+  friend class document_stream;
 };
 
 } // namespace ondemand
@@ -95774,40 +95352,25 @@ class object {
 namespace simdjson {
 
 template<>
-struct simdjson_result<westmere::ondemand::object> : public westmere::implementation_simdjson_result_base<westmere::ondemand::object> {
+struct simdjson_result<westmere::ondemand::parser> : public westmere::implementation_simdjson_result_base<westmere::ondemand::parser> {
 public:
-  simdjson_inline simdjson_result(westmere::ondemand::object &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(westmere::ondemand::parser &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> end() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
-
-  inline simdjson_result<bool> reset() noexcept;
-  inline simdjson_result<bool> is_empty() noexcept;
-  inline simdjson_result<size_t> count_fields() & noexcept;
-  inline simdjson_result<std::string_view> raw_json() noexcept;
-
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
-/* end file simdjson/generic/ondemand/object.h for westmere */
-/* including simdjson/generic/ondemand/object_iterator.h for westmere: #include "simdjson/generic/ondemand/object_iterator.h" */
-/* begin file simdjson/generic/ondemand/object_iterator.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for westmere */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for westmere: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
@@ -95817,428 +95380,2917 @@ namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-class object_iterator {
+/**
+ * A forward-only JSON array.
+ */
+class array {
 public:
   /**
-   * Create a new invalid object_iterator.
+   * Create a new invalid array.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline object_iterator() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
-  // Reads key and value, yielding them to the user.
-  // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline simdjson_result<field> operator*() noexcept;
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const object_iterator &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline object_iterator &operator++() noexcept;
+  simdjson_inline array() noexcept = default;
 
-private:
   /**
-   * The underlying JSON iterator.
+   * Begin array iteration.
    *
-   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
-   * is first used, and never changes afterwards.
+   * Part of the std::iterable interface.
    */
-  value_iterator iter{};
-
-  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
-  friend struct simdjson_result<object_iterator>;
-  friend class object;
-};
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  /**
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   *
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  /**
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
+   *
+   * @returns true if the array contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
-namespace simdjson {
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-template<>
-struct simdjson_result<westmere::ondemand::object_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::object_iterator> {
-public:
-  simdjson_inline simdjson_result(westmere::ondemand::object_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+  /**
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-  //
-  // Iterator interface
-  //
+  /**
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+protected:
+  /**
+   * Go to the end of the array, no matter where you are right now.
+   */
+  simdjson_inline error_code consume() noexcept;
 
-  // Reads key and value, yielding them to the user.
-  simdjson_inline simdjson_result<westmere::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const simdjson_result<westmere::ondemand::object_iterator> &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const simdjson_result<westmere::ondemand::object_iterator> &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &operator++() noexcept;
-};
+  /**
+   * Begin array iteration.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   */
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  /**
+   * Begin array iteration from the root.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   */
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  /**
+   * Begin array iteration.
+   *
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
+   *
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   */
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
 
-} // namespace simdjson
+  /**
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
+   *
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
+   */
+  simdjson_inline array(const value_iterator &iter) noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-/* end file simdjson/generic/ondemand/object_iterator.h for westmere */
-/* including simdjson/generic/ondemand/serialization.h for westmere: #include "simdjson/generic/ondemand/serialization.h" */
-/* begin file simdjson/generic/ondemand/serialization.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+  /**
+   * Iterator marking current position.
+   *
+   * iter.is_alive() == false indicates iteration is complete.
+   */
+  value_iterator iter{};
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
+};
 
-namespace simdjson {
-/**
- * Create a string-view instance out of a document instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept;
-/**
- * Create a string-view instance out of a value instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. The value must
- * not have been accessed previously. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept;
-/**
- * Create a string-view instance out of an object instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept;
-/**
- * Create a string-view instance out of an array instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept;
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x);
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
-/**
- * We want to support argument-dependent lookup (ADL).
- * Hence we should define operator<< in the namespace
- * where the argument (here value, object, etc.) resides.
- * Credit: @madhur4127
- * See https://github.com/simdjson/simdjson/issues/1768
- */
-namespace simdjson { namespace westmere { namespace ondemand {
+namespace simdjson {
 
-/**
- * Print JSON to an output stream.  It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The element.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x);
-#endif
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The object.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::object> x);
-#endif
-}}} // namespace simdjson::westmere::ondemand
+template<>
+struct simdjson_result<westmere::ondemand::array> : public westmere::implementation_simdjson_result_base<westmere::ondemand::array> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::array &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-/* end file simdjson/generic/ondemand/serialization.h for westmere */
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for westmere: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for westmere */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for westmere */
+/* including simdjson/generic/ondemand/array_iterator.h for westmere: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
 
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <concepts>
-#include <limits>
 
 namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
-
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
-
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
+namespace westmere {
+namespace ondemand {
 
 /**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
+ * A forward-only JSON array.
+ *
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
  */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
+class array_iterator {
+public:
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
 
-  westmere::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
-}
+  //
+  // Iterator interface
+  //
 
+  /**
+   * Get the current element.
+   *
+   * Part of the std::iterator interface.
+   */
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  /**
+   * Check if we are at the end of the JSON.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are no more elements in the JSON array.
+   */
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
+  /**
+   * Check if there are more elements in the JSON array.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are more elements in the JSON array.
+   */
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  /**
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
+   */
+  simdjson_inline array_iterator &operator++() noexcept;
 
+private:
+  value_iterator iter{};
 
-/**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
- *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
- *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
 
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
+};
 
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
-  }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
+namespace simdjson {
 
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
+template<>
+struct simdjson_result<westmere::ondemand::array_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::array_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-  if (!out) {
-    out.emplace();
-  }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
-}
+  //
+  // Iterator interface
+  //
 
-} // namespace simdjson
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<westmere::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<westmere::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &operator++() noexcept;
+};
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for westmere */
+} // namespace simdjson
 
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for westmere: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for westmere */
+/* including simdjson/generic/ondemand/document.h for westmere: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the array is first found and the iterator is just past the `{`.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
-//   depth == iter->depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter->depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the array iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
-//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
-//
-// ## Terminal State
-//
-// The terminal state has iter->depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
-//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
-//   error == SUCCESS.
-//
-
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
+/**
+ * A JSON document. It holds a json_iterator instance.
+ *
+ * Used by tokens to get text, and string buffer location.
+ *
+ * You must keep the document around during iteration.
+ */
+class document {
+public:
+  /**
+   * Create a new invalid document.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
 
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+
+  /**
+   * Cast this JSON value (inside string) to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: Calling get_string() twice on the same document is an error.
+   *
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   */
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
+  /**
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
+   *
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
+   *
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
+
+  /**
+   * Cast this JSON value to an array.
+   *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() & noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline operator value() noexcept(false);
+#endif
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  /**
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
+
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
+  /**
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+
+  /**
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  bool threaded{true};
+  #else
+  /**
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   */
+  bool threaded{false};
+  #endif
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  /**
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
+   */
+  inline void rewind() noexcept;
+  /**
+   * Returns debugging information.
+   */
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
+
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   *
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
+
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
+   */
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+  /**
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+protected:
+  /**
+   * Consumes the document.
+   */
+  simdjson_inline error_code consume() noexcept;
+
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
+
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
+
+  //
+  // Fields
+  //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+
+  friend class array_iterator;
+  friend class value;
+  friend class ondemand::parser;
+  friend class object;
+  friend class array;
+  friend class field;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
+};
+
+
+/**
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
+ */
+class document_reference {
+public:
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+private:
+  document *doc{nullptr};
+};
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::document> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
+  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator westmere::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::document_reference> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document_reference> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
+  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator westmere::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+/* end file simdjson/generic/ondemand/document.h for westmere */
+/* including simdjson/generic/ondemand/document_stream.h for westmere: #include "simdjson/generic/ondemand/document_stream.h" */
+/* begin file simdjson/generic/ondemand/document_stream.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+/** @private Custom worker class **/
+struct stage1_worker {
+  stage1_worker() noexcept = default;
+  stage1_worker(const stage1_worker&) = delete;
+  stage1_worker(stage1_worker&&) = delete;
+  stage1_worker operator=(const stage1_worker&) = delete;
+  ~stage1_worker();
+  /**
+   * We only start the thread when it is needed, not at object construction, this may throw.
+   * You should only call this once.
+   **/
+  void start_thread();
+  /**
+   * Start a stage 1 job. You should first call 'run', then 'finish'.
+   * You must call start_thread once before.
+   */
+  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
+  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
+  void finish();
+
+private:
+
+  /**
+   * Normally, we would never stop the thread. But we do in the destructor.
+   * This function is only safe assuming that you are not waiting for results. You
+   * should have called run, then finish, and be done.
+   **/
+  void stop_thread();
+
+  std::thread thread{};
+  /** These three variables define the work done by the thread. **/
+  ondemand::parser * stage1_thread_parser{};
+  size_t _next_batch_start{};
+  document_stream * owner{};
+  /**
+   * We have two state variables. This could be streamlined to one variable in the future but
+   * we use two for clarity.
+   */
+  bool has_work{false};
+  bool can_work{true};
+
+  /**
+   * We lock using a mutex.
+   */
+  std::mutex locking_mutex{};
+  std::condition_variable cond_var{};
+
+  friend class document_stream;
+};
+#endif  // SIMDJSON_THREADS_ENABLED
+
+/**
+ * A forward-only stream of documents.
+ *
+ * Produced by parser::iterate_many.
+ *
+ */
+class document_stream {
+public:
+  /**
+   * Construct an uninitialized document_stream.
+   *
+   *  ```c++
+   *  document_stream docs;
+   *  auto error = parser.iterate_many(json).get(docs);
+   *  ```
+   */
+  simdjson_inline document_stream() noexcept;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream(document_stream &&other) noexcept = default;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+
+  simdjson_inline ~document_stream() noexcept;
+
+  /**
+   * Returns the input size in bytes.
+   */
+  inline size_t size_in_bytes() const noexcept;
+
+  /**
+   * After iterating through the stream, this method
+   * returns the number of bytes that were not parsed at the end
+   * of the stream. If truncated_bytes() differs from zero,
+   * then the input was truncated maybe because incomplete JSON
+   * documents were found at the end of the stream. You
+   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   *
+   * You should only call truncated_bytes() after streaming through all
+   * documents, like so:
+   *
+   *   document_stream stream = parser.iterate_many(json,window);
+   *   for(auto & doc : stream) {
+   *      // do something with doc
+   *   }
+   *   size_t truncated = stream.truncated_bytes();
+   *
+   */
+  inline size_t truncated_bytes() const noexcept;
+
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
+
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
+
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
+
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
+
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
+
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
+
+  /**
+   * Start iterating the documents in the stream.
+   */
+  simdjson_inline iterator begin() noexcept;
+  /**
+   * The end of the stream, for iterator comparison purposes.
+   */
+  simdjson_inline iterator end() noexcept;
+
+private:
+
+  document_stream &operator=(const document_stream &) = delete; // Disallow copying
+  document_stream(const document_stream &other) = delete; // Disallow copying
+
+  /**
+   * Construct a document_stream. Does not allocate or parse anything until the iterator is
+   * used.
+   *
+   * @param parser is a reference to the parser instance used to generate this document_stream
+   * @param buf is the raw byte buffer we need to process
+   * @param len is the length of the raw byte buffer in bytes
+   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Parse the first document in the buffer. Used by begin(), to handle allocation and
+   * initialization.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+
+  /**
+   * Parse the next document found in the buffer previously given to document_stream.
+   *
+   * The content should be a valid JSON document encoded as UTF-8. If there is a
+   * UTF-8 BOM, the parser skips it.
+   *
+   * You do NOT need to pre-allocate a parser.  This function takes care of
+   * pre-allocating a capacity defined by the batch_size defined when creating the
+   * document_stream object.
+   *
+   * The function returns simdjson::EMPTY if there is no more data to be parsed.
+   *
+   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
+   * and indicates that the buffer has successfully been parsed to the end.
+   * Every document it contained has been parsed without error.
+   *
+   * The function returns an error code from simdjson/simdjson.h in case of failure
+   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
+   * the simdjson::error_message function converts these error codes into a string).
+   *
+   * You can also check validity by calling parser.is_valid(). The same parser can
+   * and should be reused for the other documents in the buffer.
+   */
+  inline void next() noexcept;
+
+  /** Move the json_iterator of the document to the location of the next document in the stream. */
+  inline void next_document() noexcept;
+
+  /** Get the next document index. */
+  inline size_t next_batch_start() const noexcept;
+
+  /** Pass the next batch through stage 1 with the given parser. */
+  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+
+  // Fields
+  ondemand::parser *parser;
+  const uint8_t *buf;
+  size_t len;
+  size_t batch_size;
+  bool allow_comma_separated;
+  /**
+   * We are going to use just one document instance. The document owns
+   * the json_iterator. It implies that we only ever pass a reference
+   * to the document to the users.
+   */
+  document doc{};
+  /** The error (or lack thereof) from the current document. */
+  error_code error;
+  size_t batch_start{0};
+  size_t doc_index{};
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
+  bool use_thread;
+
+  inline void load_from_stage1_thread() noexcept;
+
+  /** Start a thread to run stage 1 on the next batch. */
+  inline void start_stage1_thread() noexcept;
+
+  /** Wait for the stage 1 thread to finish and capture the results. */
+  inline void finish_stage1_thread() noexcept;
+
+  /** The error returned from the stage 1 thread. */
+  error_code stage1_thread_error{UNINITIALIZED};
+  /** The thread used to run stage 1 against the next batch in the background. */
+  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
+  /**
+   * The parser used to run stage 1 in the background. Will be swapped
+   * with the regular parser when finished.
+   */
+  ondemand::parser stage1_thread_parser{};
+
+  friend struct stage1_worker;
+  #endif // SIMDJSON_THREADS_ENABLED
+
+  friend class parser;
+  friend class document;
+  friend class json_iterator;
+  friend struct simdjson_result<ondemand::document_stream>;
+  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
+};  // document_stream
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+template<>
+struct simdjson_result<westmere::ondemand::document_stream> : public westmere::implementation_simdjson_result_base<westmere::ondemand::document_stream> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::document_stream &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+/* end file simdjson/generic/ondemand/document_stream.h for westmere */
+/* including simdjson/generic/ondemand/field.h for westmere: #include "simdjson/generic/ondemand/field.h" */
+/* begin file simdjson/generic/ondemand/field.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+/**
+ * A JSON field (key/value pair) in an object.
+ *
+ * Returned from object iteration.
+ *
+ * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
+ */
+class field : public std::pair<raw_json_string, value> {
+public:
+  /**
+   * Create a new invalid field.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline field() noexcept;
+
+  /**
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it.
+   *
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
+   */
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  /**
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it. The content is stored in the receiver.
+   *
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
+   */
+  template <typename string_type>
+  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
+  /**
+   * Get the key as a raw_json_string. Can be used for direct comparison with
+   * an unescaped C string: e.g., key() == "test". This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key() for a similar function which returns
+   * a more convenient std::string_view result.
+   */
+  simdjson_inline raw_json_string key() const noexcept;
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   */
+  simdjson_inline std::string_view key_raw_json_token() const noexcept;
+  /**
+   * Get the key as a string_view. This does not include the quotes and
+   * the string is unprocessed key so it may contain escape characters
+   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
+   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
+   */
+  simdjson_inline std::string_view escaped_key() const noexcept;
+  /**
+   * Get the field value.
+   */
+  simdjson_inline ondemand::value &value() & noexcept;
+  /**
+   * @overload ondemand::value &ondemand::value() & noexcept
+   */
+  simdjson_inline ondemand::value value() && noexcept;
+
+protected:
+  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
+  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
+  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
+  friend struct simdjson_result<field>;
+  friend class object_iterator;
+};
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::field> : public westmere::implementation_simdjson_result_base<westmere::ondemand::field> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::field &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  template<typename string_type>
+  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> value() noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+/* end file simdjson/generic/ondemand/field.h for westmere */
+/* including simdjson/generic/ondemand/object.h for westmere: #include "simdjson/generic/ondemand/object.h" */
+/* begin file simdjson/generic/ondemand/object.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+/**
+ * A forward-only JSON object field iterator.
+ */
+class object {
+public:
+  /**
+   * Create a new invalid object.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline object() noexcept = default;
+
+  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<object_iterator> end() noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a
+   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
+
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
+
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
+  /**
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+
+  /**
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  /**
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
+   */
+  inline void rewind() noexcept;
+  /**
+   * Returns debugging information.
+   */
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
+
+  /**
+   * Get the value associated with the given JSON pointer. We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+  /**
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the object. You should still consume values only once even if you
+   * can iterate through the object more than once. If you unescape a string or a key
+   * within the object more than once, you have unsafe code. Note that rewinding an object
+   * means that you may need to reparse it anew: it is not a free operation.
+   *
+   * @returns true if the object contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * This method scans the beginning of the object and checks whether the
+   * object is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Consumes the object and returns a string_view instance corresponding to the
+   * object as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+protected:
+  /**
+   * Go to the end of the object, no matter where you are right now.
+   */
+  simdjson_inline error_code consume() noexcept;
+  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
+  static simdjson_inline object resume(const value_iterator &iter) noexcept;
+  simdjson_inline object(const value_iterator &iter) noexcept;
+
+  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+
+  value_iterator iter{};
+
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<object>;
+};
+
+
+/**
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
+ */
+class document_reference {
+public:
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+private:
+  document *doc{nullptr};
+};
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::object> : public westmere::implementation_simdjson_result_base<westmere::ondemand::object> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::object &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> end() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at_path(std::string_view json_path) noexcept;
+
+  inline simdjson_result<bool> reset() noexcept;
+  inline simdjson_result<bool> is_empty() noexcept;
+  inline simdjson_result<size_t> count_fields() & noexcept;
+  inline simdjson_result<std::string_view> raw_json() noexcept;
+
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+/* end file simdjson/generic/ondemand/object.h for westmere */
+/* including simdjson/generic/ondemand/object_iterator.h for westmere: #include "simdjson/generic/ondemand/object_iterator.h" */
+/* begin file simdjson/generic/ondemand/object_iterator.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+class object_iterator {
+public:
+  /**
+   * Create a new invalid object_iterator.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline object_iterator() noexcept = default;
+
+  //
+  // Iterator interface
+  //
+
+  // Reads key and value, yielding them to the user.
+  // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline simdjson_result<field> operator*() noexcept;
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const object_iterator &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline object_iterator &operator++() noexcept;
+
+private:
+  /**
+   * The underlying JSON iterator.
+   *
+   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
+   * is first used, and never changes afterwards.
+   */
+  value_iterator iter{};
+
+  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
+  friend struct simdjson_result<object_iterator>;
+  friend class object;
+};
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<westmere::ondemand::object_iterator> : public westmere::implementation_simdjson_result_base<westmere::ondemand::object_iterator> {
+public:
+  simdjson_inline simdjson_result(westmere::ondemand::object_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
+  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator westmere::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  // Reads key and value, yielding them to the user.
+  simdjson_inline simdjson_result<westmere::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const simdjson_result<westmere::ondemand::object_iterator> &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const simdjson_result<westmere::ondemand::object_iterator> &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &operator++() noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+/* end file simdjson/generic/ondemand/object_iterator.h for westmere */
+/* including simdjson/generic/ondemand/serialization.h for westmere: #include "simdjson/generic/ondemand/serialization.h" */
+/* begin file simdjson/generic/ondemand/serialization.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+/**
+ * Create a string-view instance out of a document instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept;
+/**
+ * Create a string-view instance out of a value instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. The value must
+ * not have been accessed previously. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept;
+/**
+ * Create a string-view instance out of an object instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept;
+/**
+ * Create a string-view instance out of an array instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x);
+} // namespace simdjson
+
+/**
+ * We want to support argument-dependent lookup (ADL).
+ * Hence we should define operator<< in the namespace
+ * where the argument (here value, object, etc.) resides.
+ * Credit: @madhur4127
+ * See https://github.com/simdjson/simdjson/issues/1768
+ */
+namespace simdjson { namespace westmere { namespace ondemand {
+
+/**
+ * Print JSON to an output stream.  It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The element.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x);
+#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The object.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::object> x);
+#endif
+}}} // namespace simdjson::westmere::ondemand
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+/* end file simdjson/generic/ondemand/serialization.h for westmere */
+
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for westmere: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for westmere */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+#include <limits>
+
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
+
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
+
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  westmere::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for westmere */
+
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for westmere: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the array is first found and the iterator is just past the `{`.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
+//   depth == iter->depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter->depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the array iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
+//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
+//
+// ## Terminal State
+//
+// The terminal state has iter->depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
+//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
+//   error == SUCCESS.
+//
+
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
   bool has_value;
   SIMDJSON_TRY(iter.started_array().get(has_value));
   return array(iter);
@@ -96303,33 +98355,403 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
   // We don't support this, because we're returning a real element, not a position.
   if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
+
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+  westmere::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::array>(
+      std::forward<westmere::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<westmere::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for westmere */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(
+  westmere::ondemand::array_iterator &&value
+) noexcept
+  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>(std::forward<westmere::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator==(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator!=(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &simdjson_result<westmere::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
+
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
+
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
+
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
 }
 
 inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
@@ -96338,13 +98760,17 @@ inline simdjson_result<value> array::at_path(std::string_view json_path) noexcep
   return at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -96353,132 +98779,425 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
-  westmere::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::array>(
-      std::forward<westmere::ondemand::array>(value)
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
+  westmere::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(
+      std::forward<westmere::ondemand::value>(value)
     )
 {
 }
-simdjson_inline simdjson_result<westmere::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::value>(error)
 {
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return {};
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::array>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<westmere::ondemand::array>::is_empty() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  return first.find_field(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at(size_t index) noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array>::at_path(std::string_view json_path) noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first[key];
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first[key];
 }
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for westmere */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for westmere: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for westmere */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <concepts>
+#include <limits>
+
 namespace simdjson {
-namespace westmere {
-namespace ondemand {
+template <typename T>
+constexpr bool require_custom_serialization = false;
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
+
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  westmere::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
 }
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
 
-namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(
-  westmere::ondemand::array_iterator &&value
-) noexcept
-  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>(std::forward<westmere::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : westmere::implementation_simdjson_result_base<westmere::ondemand::array_iterator>({}, error)
-{
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::array_iterator>::operator*() noexcept {
+} // namespace simdjson
+
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for westmere */
+
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for westmere: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return *first;
-}
-simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator==(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+  return first.current_depth();
 }
-simdjson_inline bool simdjson_result<westmere::ondemand::array_iterator>::operator!=(const simdjson_result<westmere::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> &simdjson_result<westmere::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
@@ -97525,7 +100244,6 @@ simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westm
   return first.at_path(json_path);
 }
 
-} // namespace simdjson
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 /* end file simdjson/generic/ondemand/value-inl.h for westmere */
@@ -97549,9 +100267,23 @@ simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westm
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
   : iter{std::forward<json_iterator>(_iter)}
@@ -97816,217 +100548,845 @@ simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
   return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
+
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
+
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
+
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
+}
+
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+}
+
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
+  westmere::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::document>(
+      std::forward<westmere::ondemand::document>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::document>(
+      error
+    )
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first).get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<westmere::ondemand::document>(first);
+  return SUCCESS;
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+
+simdjson_inline bool simdjson_result<westmere::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+
+
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+
+simdjson_inline bool simdjson_result<westmere::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+
+simdjson_inline int32_t simdjson_result<westmere::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first).get<T>();
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
 }
 
+} // namespace simdjson
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
-}
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
-}
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
 } // namespace ondemand
 } // namespace westmere
 } // namespace simdjson
 
+
+
 namespace simdjson {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::simdjson_result(westmere::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<westmere::ondemand::document_reference>(std::forward<westmere::ondemand::document_reference>(value), error) {}
 
-simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
-  westmere::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document>(
-      std::forward<westmere::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document>(
-      error
-    )
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::rewind() noexcept {
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::rewind() noexcept {
   if (error()) { return error(); }
   first.rewind();
   return SUCCESS;
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::begin() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::end() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::end() & noexcept {
   return {};
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](std::string_view key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document>::get_array() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document_reference>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document>::get_object() & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document_reference>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document_reference>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::get_value() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::get_value() noexcept {
   if (error()) { return error(); }
   return first.get_value();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
-
 template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() & noexcept {
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
 template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() && noexcept {
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() && noexcept {
   if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first).get<T>();
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) & noexcept {
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>(out);
+}
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, westmere::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, westmere::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for westmere */
+/* including simdjson/generic/ondemand/document_stream-inl.h for westmere: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
+}
+
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
+}
+
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
+}
+
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
+
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
+
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
+}
+
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
+}
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
+}
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
+}
+
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
+
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
+}
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
+}
+
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+}
 template<typename T>
 simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) && noexcept {
   if (error()) { return error(); }
@@ -99878,12 +103238,26 @@ namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   return value(iter.child());
 }
@@ -99921,34 +103295,22 @@ simdjson_inline simdjson_result<value> object::find_field(const std::string_view
   return value(iter.child());
 }
 
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
-}
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
   if(error_skip) { iter.abandon(); }
@@ -99968,8 +103330,19 @@ simdjson_inline simdjson_result<object> object::started(value_iterator &iter) no
   return object(iter);
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
 simdjson_inline object::object(const value_iterator &_iter) noexcept
@@ -100253,691 +103626,1320 @@ simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_r
 {
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
+}
+
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+  }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
+}
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+}
+#endif
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+}
+
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+}
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+}
+
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
+}
+
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+namespace westmere {
+namespace ondemand {
+
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
+}
+
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
+
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
 }
 
-} // namespace simdjson
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
+
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
+
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
+
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
   } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
 #if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
+  }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-  json.remove_utf8_bom();
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-  json.remove_utf8_bom();
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
   }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
+
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
+
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
+  }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  return true;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    }
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
+}
 
-  json.remove_utf8_bom();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
   }
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
   return result;
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
   return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
+}
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
+}
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
+  if(error) { return error; }
+  return num;
+}
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for westmere */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for westmere: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace westmere {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+  }
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
+}
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
+simdjson_inline simdjson_result<westmere::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
     }
-    pos++;
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
   }
-  return true;
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
 }
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
     }
-    pos++;
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
   }
-  return true;
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
+  if(error) { return error; }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
 }
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
 }
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
   }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return result;
 }
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
   }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
   }
-  if(r[pos] != '"') { return false; }
-  return true;
+  return result;
 }
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
   }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
 
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
 
-namespace simdjson {
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
 
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
-  westmere::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+  return _json_iter->skip_child(depth());
 }
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
-{
+
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
 }
 
-} // namespace simdjson
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
+}
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
+}
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
+}
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
+}
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
+}
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
   } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
   }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
+
+
   return SUCCESS;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_root();
+  return _json_iter->peek();
+}
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+  assert_at_non_root_start();
+  return _json_iter->peek();
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  json.remove_utf8_bom();
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
+  }
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
 }
 
 } // namespace ondemand
@@ -100946,2400 +104948,2353 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(westmere::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(std::forward<westmere::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
+
 
+/* end file simdjson/generic/ondemand/amalgamated.h for westmere */
+/* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */
+/* begin file simdjson/westmere/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
+SIMDJSON_UNTARGET_REGION
+#endif
+
+/* undefining SIMDJSON_IMPLEMENTATION from "westmere" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/westmere/end.h */
+
+#endif // SIMDJSON_WESTMERE_IMPLEMENTATION_H
+/* end file simdjson/westmere/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
+/* including simdjson/lsx/ondemand.h: #include "simdjson/lsx/ondemand.h" */
+/* begin file simdjson/lsx/ondemand.h */
+#ifndef SIMDJSON_LSX_ONDEMAND_H
+#define SIMDJSON_LSX_ONDEMAND_H
+
+/* including simdjson/lsx/begin.h: #include "simdjson/lsx/begin.h" */
+/* begin file simdjson/lsx/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "lsx" */
+#define SIMDJSON_IMPLEMENTATION lsx
+/* including simdjson/lsx/base.h: #include "simdjson/lsx/base.h" */
+/* begin file simdjson/lsx/base.h */
+#ifndef SIMDJSON_LSX_BASE_H
+#define SIMDJSON_LSX_BASE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+/**
+ * Implementation for LSX.
+ */
+namespace lsx {
 
-namespace westmere {
-namespace ondemand {
+class implementation;
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
+namespace {
+namespace simd {
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
+} // namespace simd
+} // unnamed namespace
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
+} // namespace lsx
+} // namespace simdjson
+
+#endif // SIMDJSON_LSX_BASE_H
+/* end file simdjson/lsx/base.h */
+/* including simdjson/lsx/intrinsics.h: #include "simdjson/lsx/intrinsics.h" */
+/* begin file simdjson/lsx/intrinsics.h */
+#ifndef SIMDJSON_LSX_INTRINSICS_H
+#define SIMDJSON_LSX_INTRINSICS_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+// This should be the correct header whether
+// you use visual studio or other compilers.
+#include <lsxintrin.h>
+
+static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch SX");
+
+#endif //  SIMDJSON_LSX_INTRINSICS_H
+/* end file simdjson/lsx/intrinsics.h */
+/* including simdjson/lsx/bitmanipulation.h: #include "simdjson/lsx/bitmanipulation.h" */
+/* begin file simdjson/lsx/bitmanipulation.h */
+#ifndef SIMDJSON_LSX_BITMANIPULATION_H
+#define SIMDJSON_LSX_BITMANIPULATION_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmask.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace {
+
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+  return __builtin_ctzll(input_num);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num-1);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+  return __builtin_clzll(input_num);
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
+/* result might be undefined when input_num is zero */
+simdjson_inline int count_ones(uint64_t input_num) {
+  return __lsx_vpickve2gr_w(__lsx_vpcnt_d(__m128i(v2u64{input_num, 0})), 0);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
-}
+} // unnamed namespace
+} // namespace lsx
 } // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+#endif // SIMDJSON_LSX_BITMANIPULATION_H
+/* end file simdjson/lsx/bitmanipulation.h */
+/* including simdjson/lsx/bitmask.h: #include "simdjson/lsx/bitmask.h" */
+/* begin file simdjson/lsx/bitmask.h */
+#ifndef SIMDJSON_LSX_BITMASK_H
+#define SIMDJSON_LSX_BITMASK_H
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+namespace simdjson {
+namespace lsx {
+namespace {
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
+  bitmask ^= bitmask << 1;
+  bitmask ^= bitmask << 2;
+  bitmask ^= bitmask << 4;
+  bitmask ^= bitmask << 8;
+  bitmask ^= bitmask << 16;
+  bitmask ^= bitmask << 32;
+  return bitmask;
+}
+
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+/* end file simdjson/lsx/bitmask.h */
+/* including simdjson/lsx/numberparsing_defs.h: #include "simdjson/lsx/numberparsing_defs.h" */
+/* begin file simdjson/lsx/numberparsing_defs.h */
+#ifndef SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+#define SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
+#include <cstring>
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+namespace simdjson {
+namespace lsx {
+namespace numberparsing {
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+// we don't have appropriate instructions, so let us use a scalar function
+// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+/** @private */
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  uint64_t val;
+  std::memcpy(&val, chars, sizeof(uint64_t));
+  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
+  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
+}
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
+  return answer;
+}
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+} // namespace numberparsing
+} // namespace lsx
+} // namespace simdjson
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
 #endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  }
-
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
-
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
-
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
-
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+/* end file simdjson/lsx/numberparsing_defs.h */
+/* including simdjson/lsx/simd.h: #include "simdjson/lsx/simd.h" */
+/* begin file simdjson/lsx/simd.h */
+#ifndef SIMDJSON_LSX_SIMD_H
+#define SIMDJSON_LSX_SIMD_H
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
+namespace simdjson {
+namespace lsx {
+namespace {
+namespace simd {
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
+  // Forward-declared so they can be used by splat and friends.
+  template<typename Child>
+  struct base {
+    __m128i value;
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
+    // Zero constructor
+    simdjson_inline base() : value{__m128i()} {}
 
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
-}
+    // Conversion from SIMD register
+    simdjson_inline base(const __m128i _value) : value(_value) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
-}
+    // Conversion to SIMD register
+    simdjson_inline operator const __m128i&() const { return this->value; }
+    simdjson_inline operator __m128i&() { return this->value; }
+    simdjson_inline operator const v16i8&() const { return (v16i8&)this->value; }
+    simdjson_inline operator v16i8&() { return (v16i8&)this->value; }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
-}
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return __lsx_vor_v(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return __lsx_vand_v(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return __lsx_vxor_v(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return __lsx_vandn_v(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
-  return answer;
-}
+  // Forward-declared so they can be used by splat and friends.
+  template<typename T>
+  struct simd8;
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  return true;
-}
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lsx_vseq_b(lhs, rhs); }
+
+    static const int SIZE = sizeof(base<simd8<T>>::value);
+
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+      return __lsx_vor_v(__lsx_vbsll_v(*this, N), __lsx_vbsrl_v(prev_chunk, 16 - N));
     }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+  };
+
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) {
+      return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
     }
-  }
-  return SUCCESS;
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
+    simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
+    simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
-}
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) { return __lsx_vreplgr2vr_b(_value); }
+    static simdjson_inline simd8<T> zero() { return __lsx_vldi(0); }
+    static simdjson_inline simd8<T> load(const T values[16]) {
+      return __lsx_vld(reinterpret_cast<const __m128i *>(values), 0);
+    }
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
-}
+    // Store to array
+    simdjson_inline void store(T dst[16]) const {
+      return __lsx_vst(*this, reinterpret_cast<__m128i *>(dst), 0);
+    }
 
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
-  }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lsx_vadd_b(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lsx_vsub_b(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-simdjson_inline simdjson_result<westmere::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return __lsx_vshuf_b(lookup_table, lookup_table, *this);
     }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
+    // get written.
+    template<typename L>
+    simdjson_inline void compress(uint16_t mask, L * output) const {
+      using internal::thintable_epi8;
+      using internal::BitsSetTable256mul2;
+      using internal::pshufb_combine_table;
+      // this particular implementation was inspired by haswell
+      // lsx do it in 2 steps, first 8 bytes and then second 8 bytes...
+      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
+      uint8_t mask2 = uint8_t(mask >> 8); // second least significant 8 bits
+      // next line just loads the 64-bit values thintable_epi8[mask1] and
+      // thintable_epi8[mask2] into a 128-bit register.
+      __m128i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808};
+      // this is the version "nearly pruned"
+      __m128i pruned = __lsx_vshuf_b(*this, *this, shufmask);
+      // we still need to put the  pieces back together.
+      // we compute the popcount of the first words:
+      int pop1 = BitsSetTable256mul2[mask1];
+      // then load the corresponding mask
+      __m128i compactmask = __lsx_vldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
+      __m128i answer = __lsx_vshuf_b(pruned, pruned, compactmask);
+      __lsx_vst(answer, reinterpret_cast<uint8_t*>(output), 0);
+    }
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
+    }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
-  }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
-  }
-  return result;
-}
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t values[16]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) : simd8({
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+      }) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lsx_vmax_b(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lsx_vmin_b(*this, other); }
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lsx_vslt_b(other, *this); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lsx_vslt_b(*this, other); }
+  };
 
-  return _json_iter->skip_child(depth());
-}
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) : simd8(__m128i(v16u8{
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    })) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
-}
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lsx_vsadd_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lsx_vssub_bu(*this, other); }
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lsx_vmax_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lsx_vmin_bu(other, *this); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
-}
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+    simdjson_inline bool is_ascii() const { return 0 == __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
+    simdjson_inline bool bits_not_set_anywhere() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
+      return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(__lsx_vand_v(*this, bits)), 0);
+    }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lsx_vsrli_b(*this, N)); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); }
+  };
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
-}
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
-}
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
-}
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
-}
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
-}
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      uint16_t mask1 = uint16_t(mask);
+      uint16_t mask2 = uint16_t(mask >> 16);
+      uint16_t mask3 = uint16_t(mask >> 32);
+      uint16_t mask4 = uint16_t(mask >> 48);
+      __m128i zcnt = __lsx_vpcnt_h(__m128i(v2u64{~mask, 0}));
+      uint64_t zcnt1 = __lsx_vpickve2gr_hu(zcnt, 0);
+      uint64_t zcnt2 = __lsx_vpickve2gr_hu(zcnt, 1);
+      uint64_t zcnt3 = __lsx_vpickve2gr_hu(zcnt, 2);
+      uint64_t zcnt4 = __lsx_vpickve2gr_hu(zcnt, 3);
+      uint8_t *voutput = reinterpret_cast<uint8_t*>(output);
+      // There should be a critical value which processes in scaler is faster.
+      if (zcnt1)
+        this->chunks[0].compress(mask1, reinterpret_cast<T*>(voutput));
+      voutput += zcnt1;
+      if (zcnt2)
+        this->chunks[1].compress(mask2, reinterpret_cast<T*>(voutput));
+      voutput += zcnt2;
+      if (zcnt3)
+        this->chunks[2].compress(mask3, reinterpret_cast<T*>(voutput));
+      voutput += zcnt3;
+      if (zcnt4)
+        this->chunks[3].compress(mask4, reinterpret_cast<T*>(voutput));
+      voutput += zcnt4;
+      return reinterpret_cast<uint64_t>(voutput) - reinterpret_cast<uint64_t>(output);
+    }
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
+      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
+      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
+    }
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
+    simdjson_inline uint64_t to_bitmask() const {
+      __m128i mask1 = __lsx_vmskltz_b(this->chunks[0]);
+      __m128i mask2 = __lsx_vmskltz_b(this->chunks[1]);
+      __m128i mask3 = __lsx_vmskltz_b(this->chunks[2]);
+      __m128i mask4 = __lsx_vmskltz_b(this->chunks[3]);
+      mask1 = __lsx_vilvl_h(mask2, mask1);
+      mask2 = __lsx_vilvl_h(mask4, mask3);
+      return __lsx_vpickve2gr_du(__lsx_vilvl_w(mask2, mask1), 0);
+    }
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
-}
+    simdjson_inline simd8<T> reduce_or() const {
+      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
+    }
 
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] == mask,
+        this->chunks[1] == mask,
+        this->chunks[2] == mask,
+        this->chunks[3] == mask
+      ).to_bitmask();
+    }
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return  simd8x64<bool>(
+        this->chunks[0] == other.chunks[0],
+        this->chunks[1] == other.chunks[1],
+        this->chunks[2] == other.chunks[2],
+        this->chunks[3] == other.chunks[3]
+      ).to_bitmask();
+    }
 
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
-  }
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] <= mask,
+        this->chunks[1] <= mask,
+        this->chunks[2] <= mask,
+        this->chunks[3] <= mask
+      ).to_bitmask();
+    }
+  }; // struct simd8x64<T>
 
+} // namespace simd
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-  return SUCCESS;
-}
+#endif // SIMDJSON_LSX_SIMD_H
+/* end file simdjson/lsx/simd.h */
+/* including simdjson/lsx/stringparsing_defs.h: #include "simdjson/lsx/stringparsing_defs.h" */
+/* begin file simdjson/lsx/stringparsing_defs.h */
+#ifndef SIMDJSON_LSX_STRINGPARSING_DEFS_H
+#define SIMDJSON_LSX_STRINGPARSING_DEFS_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/simd.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+namespace simdjson {
+namespace lsx {
+namespace {
 
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+using namespace simd;
 
-  assert_at_non_root_start();
-  return _json_iter->peek();
-}
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
+public:
+  static constexpr uint32_t BYTES_PROCESSED = 32;
+  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
 
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
+  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
+  simdjson_inline bool has_backslash() { return bs_bits != 0; }
+  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
+  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
 
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
+  uint32_t bs_bits;
+  uint32_t quote_bits;
+}; // struct backslash_and_quote
 
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 31 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v0(src);
+  simd8<uint8_t> v1(src + sizeof(v0));
+  v0.store(dst);
+  v1.store(dst + sizeof(v0));
 
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
+  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on LSX; therefore, we
+  // smash them together into a 64-byte mask and get the bitmask from there.
+  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
+  return {
+    uint32_t(bs_and_quote),      // bs_bits
+    uint32_t(bs_and_quote >> 32) // quote_bits
+  };
 }
 
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
-}
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
-}
+#endif // SIMDJSON_LSX_STRINGPARSING_DEFS_H
+/* end file simdjson/lsx/stringparsing_defs.h */
 
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
-}
+#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
+/* end file simdjson/lsx/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for lsx: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for lsx */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
+#endif
 
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for lsx: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+namespace simdjson {
+namespace lsx {
+/**
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
+ */
+namespace ondemand {
 
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
-}
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
 
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
-}
+/** @copydoc simdjson::lsx::number_type */
+using number_type = simdjson::lsx::number_type;
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
-}
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
-}
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
 
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for lsx */
+/* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for lsx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
+#include <concepts>
+namespace simdjson {
 
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
+namespace tag_invoke_fn_ns {
+void tag_invoke();
 
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
   }
-}
-
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
-}
-
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
-}
-
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
+};
+} // namespace tag_invoke_fn_ns
 
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
 
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
-}
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
 
-namespace simdjson {
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
 
-simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(westmere::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(std::forward<westmere::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(error) {}
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
 
-} // namespace simdjson
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
 
+struct deserialize_tag;
 
-/* end file simdjson/generic/ondemand/amalgamated.h for westmere */
-/* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */
-/* begin file simdjson/westmere/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
-SIMDJSON_UNTARGET_REGION
-#endif
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
 
-/* undefining SIMDJSON_IMPLEMENTATION from "westmere" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/westmere/end.h */
+template <typename T, typename ValT = lsx::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
 
-#endif // SIMDJSON_WESTMERE_IMPLEMENTATION_H
-/* end file simdjson/westmere/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
-/* including simdjson/lsx/ondemand.h: #include "simdjson/lsx/ondemand.h" */
-/* begin file simdjson/lsx/ondemand.h */
-#ifndef SIMDJSON_LSX_ONDEMAND_H
-#define SIMDJSON_LSX_ONDEMAND_H
+template <typename T, typename ValT = lsx::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-/* including simdjson/lsx/begin.h: #include "simdjson/lsx/begin.h" */
-/* begin file simdjson/lsx/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "lsx" */
-#define SIMDJSON_IMPLEMENTATION lsx
-/* including simdjson/lsx/base.h: #include "simdjson/lsx/base.h" */
-/* begin file simdjson/lsx/base.h */
-#ifndef SIMDJSON_LSX_BASE_H
-#define SIMDJSON_LSX_BASE_H
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-namespace simdjson {
-/**
- * Implementation for LSX.
- */
-namespace lsx {
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = lsx::ondemand::value;
+  using document_type = lsx::ondemand::document;
+  using document_reference_type = lsx::ondemand::document_reference;
 
-class implementation;
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-namespace {
-namespace simd {
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
-} // namespace simd
-} // unnamed namespace
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-} // namespace lsx
-} // namespace simdjson
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-#endif // SIMDJSON_LSX_BASE_H
-/* end file simdjson/lsx/base.h */
-/* including simdjson/lsx/intrinsics.h: #include "simdjson/lsx/intrinsics.h" */
-/* begin file simdjson/lsx/intrinsics.h */
-#ifndef SIMDJSON_LSX_INTRINSICS_H
-#define SIMDJSON_LSX_INTRINSICS_H
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+} deserialize{};
 
-// This should be the correct header whether
-// you use visual studio or other compilers.
-#include <lsxintrin.h>
+} // namespace simdjson
 
-static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch SX");
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
 
-#endif //  SIMDJSON_LSX_INTRINSICS_H
-/* end file simdjson/lsx/intrinsics.h */
-/* including simdjson/lsx/bitmanipulation.h: #include "simdjson/lsx/bitmanipulation.h" */
-/* begin file simdjson/lsx/bitmanipulation.h */
-#ifndef SIMDJSON_LSX_BITMANIPULATION_H
-#define SIMDJSON_LSX_BITMANIPULATION_H
+/* end file simdjson/generic/ondemand/deserialize.h for lsx */
+/* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmask.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
-namespace {
+namespace ondemand {
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-  return __builtin_ctzll(input_num);
-}
+/**
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
+ *
+ * @private This is not intended for external use.
+ */
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
+  /**
+   * The starting token index for this value
+   */
+  token_position _start_position{};
 
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num-1);
-}
+public:
+  simdjson_inline value_iterator() noexcept = default;
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-  return __builtin_clzll(input_num);
-}
+  /**
+   * Denote that we're starting a document.
+   */
+  simdjson_inline void start_document() noexcept;
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int count_ones(uint64_t input_num) {
-  return __lsx_vpickve2gr_w(__lsx_vpcnt_d(__m128i(v2u64{input_num, 0})), 0);
-}
+  /**
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   *
+   * Optimized for scalars.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
 
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-}
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
 
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Tell whether the iterator is at the start of the value
+   */
+  simdjson_inline bool at_start() const noexcept;
 
-#endif // SIMDJSON_LSX_BITMANIPULATION_H
-/* end file simdjson/lsx/bitmanipulation.h */
-/* including simdjson/lsx/bitmask.h: #include "simdjson/lsx/bitmask.h" */
-/* begin file simdjson/lsx/bitmask.h */
-#ifndef SIMDJSON_LSX_BITMASK_H
-#define SIMDJSON_LSX_BITMASK_H
+  /**
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   */
+  simdjson_inline bool is_open() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Tell whether the value is at an object's first field (just after the {).
+   */
+  simdjson_inline bool at_first_field() const noexcept;
 
-namespace simdjson {
-namespace lsx {
-namespace {
+  /**
+   * Abandon all iteration.
+   */
+  simdjson_inline void abandon() noexcept;
 
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
-  bitmask ^= bitmask << 1;
-  bitmask ^= bitmask << 2;
-  bitmask ^= bitmask << 4;
-  bitmask ^= bitmask << 8;
-  bitmask ^= bitmask << 16;
-  bitmask ^= bitmask << 32;
-  return bitmask;
-}
+  /**
+   * Get the child value as a value_iterator.
+   */
+  simdjson_inline value_iterator child_value() const noexcept;
 
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Get the depth of this value.
+   */
+  simdjson_inline int32_t depth() const noexcept;
 
-#endif
-/* end file simdjson/lsx/bitmask.h */
-/* including simdjson/lsx/numberparsing_defs.h: #include "simdjson/lsx/numberparsing_defs.h" */
-/* begin file simdjson/lsx/numberparsing_defs.h */
-#ifndef SIMDJSON_LSX_NUMBERPARSING_DEFS_H
-#define SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+  /**
+   * Get the JSON type of this value.
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * @addtogroup object Object iteration
+   *
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
+   *
+   * @{
+   */
 
-#include <cstring>
+  /**
+   * Start an object iteration.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  /**
+   * Start an object iteration from the root.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  /**
+   * Checks whether an object could be started from the root. May be called by start_root_object.
+   *
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  /**
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  /**
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
-namespace simdjson {
-namespace lsx {
-namespace numberparsing {
+  /**
+   * Moves to the next field in an object.
+   *
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
 
-// we don't have appropriate instructions, so let us use a scalar function
-// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
-/** @private */
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  uint64_t val;
-  std::memcpy(&val, chars, sizeof(uint64_t));
-  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
-  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
-  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
-}
+  /**
+   * Get the current field's key.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
 
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
-  return answer;
-}
+  /**
+   * Pass the : in the field and move to its value.
+   */
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
 
-} // namespace numberparsing
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Find the next field with the given key.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
 
-#ifndef SIMDJSON_SWAR_NUMBER_PARSING
-#if SIMDJSON_IS_BIG_ENDIAN
-#define SIMDJSON_SWAR_NUMBER_PARSING 0
-#else
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-#endif
-#endif
+  /**
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
 
-#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
-/* end file simdjson/lsx/numberparsing_defs.h */
-/* including simdjson/lsx/simd.h: #include "simdjson/lsx/simd.h" */
-/* begin file simdjson/lsx/simd.h */
-#ifndef SIMDJSON_LSX_SIMD_H
-#define SIMDJSON_LSX_SIMD_H
+  /**
+   * Find the field with the given key without regard to order, and *without* unescaping.
+   *
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /** @} */
 
-namespace simdjson {
-namespace lsx {
-namespace {
-namespace simd {
+  /**
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
+   */
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename Child>
-  struct base {
-    __m128i value;
+  /**
+   * Check for an opening [ and start an array iteration.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  /**
+   * Check for an opening [ and start an array iteration while at the root.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  /**
+   * Checks whether an array could be started from the root. May be called by start_root_array.
+   *
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  /**
+   * Start an array iteration, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  /**
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
-    // Zero constructor
-    simdjson_inline base() : value{__m128i()} {}
+  /**
+   * Moves to the next element in an array.
+   *
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
-    // Conversion from SIMD register
-    simdjson_inline base(const __m128i _value) : value(_value) {}
+  /**
+   * Get a child value iterator.
+   */
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
 
-    // Conversion to SIMD register
-    simdjson_inline operator const __m128i&() const { return this->value; }
-    simdjson_inline operator __m128i&() { return this->value; }
-    simdjson_inline operator const v16i8&() const { return (v16i8&)this->value; }
-    simdjson_inline operator v16i8&() { return (v16i8&)this->value; }
+  /** @} */
 
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return __lsx_vor_v(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return __lsx_vand_v(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return __lsx_vxor_v(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return __lsx_vandn_v(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
+  /**
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
+   */
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename T>
-  struct simd8;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
 
-    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lsx_vseq_b(lhs, rhs); }
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
 
-    static const int SIZE = sizeof(base<simd8<T>>::value);
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-      return __lsx_vor_v(__lsx_vbsll_v(*this, N), __lsx_vbsrl_v(prev_chunk, 16 - N));
-    }
-  };
+  /** @} */
+protected:
+  /**
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  /**
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  /**
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) {
-      return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
-    }
+  /**
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
+   *
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
 
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
 
-    simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
-    simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
+   *
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   */
 
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) { return __lsx_vreplgr2vr_b(_value); }
-    static simdjson_inline simd8<T> zero() { return __lsx_vldi(0); }
-    static simdjson_inline simd8<T> load(const T values[16]) {
-      return __lsx_vld(reinterpret_cast<const __m128i *>(values), 0);
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
 
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
 
-    // Store to array
-    simdjson_inline void store(T dst[16]) const {
-      return __lsx_vst(*this, reinterpret_cast<__m128i *>(dst), 0);
-    }
 
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lsx_vadd_b(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lsx_vsub_b(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
 
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  /**
+   * Advance to a place expecting a value (increasing depth).
+   *
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
+   */
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
 
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return __lsx_vshuf_b(lookup_table, lookup_table, *this);
-    }
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
 
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
-    // get written.
-    template<typename L>
-    simdjson_inline void compress(uint16_t mask, L * output) const {
-      using internal::thintable_epi8;
-      using internal::BitsSetTable256mul2;
-      using internal::pshufb_combine_table;
-      // this particular implementation was inspired by haswell
-      // lsx do it in 2 steps, first 8 bytes and then second 8 bytes...
-      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
-      uint8_t mask2 = uint8_t(mask >> 8); // second least significant 8 bits
-      // next line just loads the 64-bit values thintable_epi8[mask1] and
-      // thintable_epi8[mask2] into a 128-bit register.
-      __m128i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808};
-      // this is the version "nearly pruned"
-      __m128i pruned = __lsx_vshuf_b(*this, *this, shufmask);
-      // we still need to put the  pieces back together.
-      // we compute the popcount of the first words:
-      int pop1 = BitsSetTable256mul2[mask1];
-      // then load the corresponding mask
-      __m128i compactmask = __lsx_vldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
-      __m128i answer = __lsx_vshuf_b(pruned, pruned, compactmask);
-      __lsx_vst(answer, reinterpret_cast<uint8_t*>(output), 0);
-    }
+  simdjson_inline bool is_at_start() const noexcept;
+  /**
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
+   *
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   */
+  simdjson_inline bool is_at_iterator_start() const noexcept;
 
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
-    }
-  };
+  /**
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
+   *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
+   */
+  simdjson_inline bool is_at_key() const noexcept;
 
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t values[16]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) : simd8({
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-      }) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lsx_vmax_b(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lsx_vmin_b(*this, other); }
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lsx_vslt_b(other, *this); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lsx_vslt_b(*this, other); }
-  };
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
 
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) : simd8(__m128i(v16u8{
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    })) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lsx_vsadd_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lsx_vssub_bu(*this, other); }
+  friend class document;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lsx_vmax_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lsx_vmin_bu(other, *this); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
-    simdjson_inline bool is_ascii() const { return 0 == __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
-    simdjson_inline bool bits_not_set_anywhere() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
-      return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(__lsx_vand_v(*this, bits)), 0);
-    }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lsx_vsrli_b(*this, N)); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); }
-  };
+namespace simdjson {
 
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
+template<>
+struct simdjson_result<lsx::ondemand::value_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value_iterator> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
 
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
+} // namespace simdjson
 
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for lsx */
+/* including simdjson/generic/ondemand/value.h for lsx: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      uint16_t mask1 = uint16_t(mask);
-      uint16_t mask2 = uint16_t(mask >> 16);
-      uint16_t mask3 = uint16_t(mask >> 32);
-      uint16_t mask4 = uint16_t(mask >> 48);
-      __m128i zcnt = __lsx_vpcnt_h(__m128i(v2u64{~mask, 0}));
-      uint64_t zcnt1 = __lsx_vpickve2gr_hu(zcnt, 0);
-      uint64_t zcnt2 = __lsx_vpickve2gr_hu(zcnt, 1);
-      uint64_t zcnt3 = __lsx_vpickve2gr_hu(zcnt, 2);
-      uint64_t zcnt4 = __lsx_vpickve2gr_hu(zcnt, 3);
-      uint8_t *voutput = reinterpret_cast<uint8_t*>(output);
-      // There should be a critical value which processes in scaler is faster.
-      if (zcnt1)
-        this->chunks[0].compress(mask1, reinterpret_cast<T*>(voutput));
-      voutput += zcnt1;
-      if (zcnt2)
-        this->chunks[1].compress(mask2, reinterpret_cast<T*>(voutput));
-      voutput += zcnt2;
-      if (zcnt3)
-        this->chunks[2].compress(mask3, reinterpret_cast<T*>(voutput));
-      voutput += zcnt3;
-      if (zcnt4)
-        this->chunks[3].compress(mask4, reinterpret_cast<T*>(voutput));
-      voutput += zcnt4;
-      return reinterpret_cast<uint64_t>(voutput) - reinterpret_cast<uint64_t>(output);
-    }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
-      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
-      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
-    }
+#include <type_traits>
 
-    simdjson_inline uint64_t to_bitmask() const {
-      __m128i mask1 = __lsx_vmskltz_b(this->chunks[0]);
-      __m128i mask2 = __lsx_vmskltz_b(this->chunks[1]);
-      __m128i mask3 = __lsx_vmskltz_b(this->chunks[2]);
-      __m128i mask4 = __lsx_vmskltz_b(this->chunks[3]);
-      mask1 = __lsx_vilvl_h(mask2, mask1);
-      mask2 = __lsx_vilvl_h(mask4, mask3);
-      return __lsx_vpickve2gr_du(__lsx_vilvl_w(mask2, mask1), 0);
-    }
+namespace simdjson {
 
-    simdjson_inline simd8<T> reduce_or() const {
-      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
-    }
+namespace lsx {
+namespace ondemand {
+/**
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
+ */
+class value {
+public:
+  /**
+   * Create a new invalid value.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline value() noexcept = default;
 
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] == mask,
-        this->chunks[1] == mask,
-        this->chunks[2] == mask,
-        this->chunks[3] == mask
-      ).to_bitmask();
-    }
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
 
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return  simd8x64<bool>(
-        this->chunks[0] == other.chunks[0],
-        this->chunks[1] == other.chunks[1],
-        this->chunks[2] == other.chunks[2],
-        this->chunks[3] == other.chunks[3]
-      ).to_bitmask();
-    }
 
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] <= mask,
-        this->chunks[1] <= mask,
-        this->chunks[2] <= mask,
-        this->chunks[3] <= mask
-      ).to_bitmask();
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
     }
-  }; // struct simd8x64<T>
+#endif
+  }
 
-} // namespace simd
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
-#endif // SIMDJSON_LSX_SIMD_H
-/* end file simdjson/lsx/simd.h */
-/* including simdjson/lsx/stringparsing_defs.h: #include "simdjson/lsx/stringparsing_defs.h" */
-/* begin file simdjson/lsx/stringparsing_defs.h */
-#ifndef SIMDJSON_LSX_STRINGPARSING_DEFS_H
-#define SIMDJSON_LSX_STRINGPARSING_DEFS_H
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/simd.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
-namespace simdjson {
-namespace lsx {
-namespace {
+  /**
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
-using namespace simd;
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 32;
-  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
-  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
-  simdjson_inline bool has_backslash() { return bs_bits != 0; }
-  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
-  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
-  uint32_t bs_bits;
-  uint32_t quote_bits;
-}; // struct backslash_and_quote
+  /**
+   * Cast this JSON value (inside string) to a double
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
 
-simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 31 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v0(src);
-  simd8<uint8_t> v1(src + sizeof(v0));
-  v0.store(dst);
-  v1.store(dst + sizeof(v0));
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Equivalent to get<std::string_view>().
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
 
-  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on LSX; therefore, we
-  // smash them together into a 64-byte mask and get the bitmask from there.
-  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
-  return {
-    uint32_t(bs_and_quote),      // bs_bits
-    uint32_t(bs_and_quote >> 32) // quote_bits
-  };
-}
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   */
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
 
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Cast this JSON value to a "wobbly" string.
+   *
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
 
-#endif // SIMDJSON_LSX_STRINGPARSING_DEFS_H
-/* end file simdjson/lsx/stringparsing_defs.h */
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
 
-#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
-/* end file simdjson/lsx/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for lsx: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for lsx */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
+  /**
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
+   *
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
+   *
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() noexcept(false);
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Equivalent to get<std::string_view>().
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
 #endif
 
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for lsx: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
+  /**
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   *
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
 
-namespace simdjson {
-namespace lsx {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
-/** @copydoc simdjson::lsx::number_type */
-using number_type = simdjson::lsx::number_type;
+  /**
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  /**
+   * Checks whether the value is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the value is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
+   */
+  simdjson_inline std::string_view raw_json_token() noexcept;
 
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
+  /**
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for lsx */
-/* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for lsx */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
 
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
-#include <concepts>
-namespace simdjson {
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
 
-namespace tag_invoke_fn_ns {
-void tag_invoke();
 
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
+protected:
+  /**
+   * Create a value.
+   */
+  simdjson_inline value(const value_iterator &iter) noexcept;
 
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
+  /**
+   * Skip this value, allowing iteration to continue.
+   */
+  simdjson_inline void skip() noexcept;
 
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
+  /**
+   * Start a value at the current position.
+   *
+   * (It should already be started; this is just a self-documentation method.)
+   */
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
 
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
+  /**
+   * Resume a value.
+   */
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
 
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+  /**
+   * Get the object, starting or resuming it as necessary
+   */
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
 
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
 
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+  value_iterator iter{};
 
+  friend class document;
+  friend class array_iterator;
+  friend class field;
+  friend class object;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
+  friend class field;
+};
 
-struct deserialize_tag;
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+namespace simdjson {
 
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+template<>
+struct simdjson_result<lsx::ondemand::value> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-template <typename T, typename ValT = lsx::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() noexcept;
 
-template <typename T, typename ValT = lsx::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-template <typename T, typename ValT = lsx::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
 
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = lsx::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
 
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = lsx::ondemand::value;
-  using document_type = lsx::ondemand::document;
-  using document_reference_type = lsx::ondemand::document_reference;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lsx::ondemand::array() noexcept(false);
+  simdjson_inline operator lsx::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
 
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) noexcept;
 
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) noexcept = delete;
 
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
+  /**
+   * Get the type of this JSON value.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   */
+  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
 
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-} deserialize{};
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
 
 } // namespace simdjson
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for lsx */
-/* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for lsx */
+/* including simdjson/generic/ondemand/logger.h for lsx: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-/**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
- *
- * @private This is not intended for external use.
- */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
-
-public:
-  simdjson_inline value_iterator() noexcept = default;
-
-  /**
-   * Denote that we're starting a document.
-   */
-  simdjson_inline void start_document() noexcept;
-
-  /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
-   *
-   * Optimized for scalars.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
-
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
-
-  /**
-   * Tell whether the iterator is at the start of the value
-   */
-  simdjson_inline bool at_start() const noexcept;
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
 
-  /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
-   */
-  simdjson_inline bool is_open() const noexcept;
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
+};
 
-  /**
-   * Tell whether the value is at an object's first field (just after the {).
-   */
-  simdjson_inline bool at_first_field() const noexcept;
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
+#else
+  static constexpr const bool LOG_ENABLED = false;
+#endif
 
-  /**
-   * Abandon all iteration.
-   */
-  simdjson_inline void abandon() noexcept;
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
 
-  /**
-   * Get the child value as a value_iterator.
-   */
-  simdjson_inline value_iterator child_value() const noexcept;
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
 
-  /**
-   * Get the depth of this value.
-   */
-  simdjson_inline int32_t depth() const noexcept;
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
 
-  /**
-   * Get the JSON type of this value.
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
+} // namespace logger
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-  /**
-   * @addtogroup object Object iteration
-   *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
-   *
-   * @{
-   */
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for lsx */
+/* including simdjson/generic/ondemand/token_iterator.h for lsx: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
 
-  /**
-   * Start an object iteration.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
-  /**
-   * Start an object iteration from the root.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
-  /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
-   *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
-  /**
-   * Start an object iteration after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
-  /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Moves to the next field in an object.
-   *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
+ *
+ * @private This is not intended for external use.
+ */
+class token_iterator {
+public:
   /**
-   * Get the current field's key.
+   * Create a new invalid token_iterator.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
 
   /**
-   * Pass the : in the field and move to its value.
+   * Advance to the next token (returning the current one).
    */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
-
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
   /**
-   * Find the next field with the given key.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * Reports the current offset in bytes from the start of the underlying buffer.
    */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
-
+  simdjson_inline uint32_t current_offset() const noexcept;
   /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
+   * Get the JSON text for a given token (relative).
    *
-   * This means the iterator must be sitting at the next key:
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
-
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
-   *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
+   * Get the maximum length of the JSON text for a given token.
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * The length will include any whitespace at the end of the token.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
-
-  /** @} */
-
-  /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
 
   /**
-   * Check for an opening [ and start an array iteration.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
-  /**
-   * Check for an opening [ and start an array iteration while at the root.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
-  /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
+   * Get the JSON text for a given token.
    *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
-  /**
-   * Start an array iteration, after the user has already checked and moved past the [.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * @param position The position of the token.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * The length will include any whitespace at the end of the token.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @param position The position of the token.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
-
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Moves to the next element in an array.
+   * Get the maximum length of the JSON text for a root token.
    *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * The length will include any whitespace at the end of the token.
    *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
+   * @param position The position of the token (start of the document).
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
-
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * Get a child value iterator.
+   * Return the current index.
    */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
-
-  /** @} */
-
+  simdjson_inline token_position position() const noexcept;
   /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
+   * Reset to a previously saved index.
    */
+  simdjson_inline void set_position(token_position target_position) noexcept;
 
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
-
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
 
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
 
-  /** @} */
 protected:
-  /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
-  /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
-  /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
-   *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
-
-  /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
-   *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
-
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
 
   /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
-   *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
-   *
-   * ({"globals":{"a":{"shadowable":[}}}})
-   *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
-   *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
+   * Get the index of the JSON text for a given token (relative).
    *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
-
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
-
-
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
-
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
   /**
-   * Advance to a place expecting a value (increasing depth).
+   * Get the index of the JSON text for a given token.
    *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
-   */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
-
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
-
-  simdjson_inline bool is_at_start() const noexcept;
-  /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
-   */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
-
-  /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
+   * @param position The position of the token.
    *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
    */
-  simdjson_inline bool is_at_key() const noexcept;
-
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
-
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
 
-  /** @copydoc error_code json_iterator::position() const noexcept; */
-  simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+  const uint8_t *buf{};
+  token_position _position{};
 
-  friend class document;
+  friend class json_iterator;
+  friend class value_iterator;
   friend class object;
-  friend class array;
-  friend class value;
-  friend class field;
-}; // value_iterator
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+};
 
 } // namespace ondemand
 } // namespace lsx
@@ -103348,711 +107303,502 @@ class value_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::value_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value_iterator> {
+struct simdjson_result<lsx::ondemand::token_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::token_iterator> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::token_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for lsx */
-/* including simdjson/generic/ondemand/value.h for lsx: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for lsx */
+/* including simdjson/generic/ondemand/json_iterator.h for lsx: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <type_traits>
-
-namespace simdjson {
-
-namespace lsx {
-namespace ondemand {
-/**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
- */
-class value {
-public:
-  /**
-   * Create a new invalid value.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline value() noexcept = default;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
+ */
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
   /**
-   * Cast this JSON value to an object.
+   * Next free location in the string buffer.
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
    */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
-
+  uint8_t *_string_buf_loc{};
   /**
-   * Cast this JSON value to an unsigned integer.
+   * JSON error, if there is one.
    *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a unsigned integer.
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
    *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-
+  error_code error{SUCCESS};
   /**
-   * Cast this JSON value to a signed integer.
+   * Depth of the current token in the JSON.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-
+  depth_t _depth{};
   /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
    */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-
+  token_position _root{};
   /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
    */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
+  bool _streaming{false};
 
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
-   * Cast this JSON value (inside string) to a double
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * Skips a JSON value, whether it is a scalar, array or object.
    */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Tell whether the iterator is still at the start
    */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  simdjson_inline bool at_root() const noexcept;
 
   /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
    */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline bool streaming() const noexcept;
 
   /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Get the root value iterator
    */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline token_position root_position() const noexcept;
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Assert that we are at the document depth (== 1)
    */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-
+  simdjson_inline void assert_at_document_depth() const noexcept;
   /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   * Assert that we are at the root of the document
    */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline void assert_at_root() const noexcept;
 
   /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   * Tell whether the iterator is at the EOF mark
    */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_inline bool at_end() const noexcept;
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
+   * Tell whether the iterator is live (has not been moved).
    */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline bool is_alive() const noexcept;
+
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
    */
-  simdjson_inline operator array() noexcept(false);
+  simdjson_inline void abandon() noexcept;
+
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   * Advance the current token without modifying depth.
    */
-  simdjson_inline operator object() noexcept(false);
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+
   /**
-   * Cast this JSON value to an unsigned integer.
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * @return whether there is a single token
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline bool is_single_token() const noexcept;
+
   /**
-   * Cast this JSON value to a signed integer.
+   * Assert that there are at least the given number of tokens left.
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   * Has no effect in release builds.
    */
-  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
   /**
-   * Cast this JSON value to a double.
+   * Assert that the given position addresses an actual token (is within bounds).
    *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * Has no effect in release builds.
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
   /**
-   * Cast this JSON value to a string.
+   * Get the JSON text for a given token (relative).
    *
-   * The string is guaranteed to be valid UTF-8.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Equivalent to get<std::string_view>().
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
+   * The length will include any whitespace at the end of the token.
    *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_inline operator bool() noexcept(false);
-#endif
-
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * Get a pointer to the current location in the input buffer.
    *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Part of the std::iterable interface.
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Get the JSON text for a given token.
    *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
+   * @param position The position of the token to retrieve.
    *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   * Get the maximum length of the JSON text for the current root token.
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * The length will include any whitespace at the end of the token.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
-
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+   * Get the JSON text for the last token in the document.
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * Ascend one level.
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * Validates that the depth - 1 == parent_depth.
    *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @param parent_depth the expected parent depth.
    */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
 
   /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   * Descend one level.
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  /**
-   * Checks whether the value is a string.
+   * Validates that the new depth == child_depth.
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @param child_depth the expected child depth.
    */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
 
   /**
-   * Checks whether the value is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
-   *
-   * @returns true if the number if negative.
+   * Get current depth.
    */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline depth_t depth() const noexcept;
+
   /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
+   * Get current (writeable) location in the string buffer.
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
   /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
   /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   *
-   * See also value::raw_json().
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline std::string_view raw_json_token() noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
 
   /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
+
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
+   */
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
+
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
+
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
 
   /**
    * Returns the current location in the document if in bounds.
    */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  inline simdjson_result<const char *> current_location() const noexcept;
 
   /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
    */
-  simdjson_inline int32_t current_depth() const noexcept;
+  inline void rewind() noexcept;
+  /**
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
+   */
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
+  simdjson_inline token_position last_position() const noexcept;
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
+  simdjson_inline token_position end_position() const noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
+
+  friend class document;
+  friend class document_stream;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
+  friend class field;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lsx::ondemand::json_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::json_iterator> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::json_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+
+  simdjson_inline simdjson_result() noexcept = default;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for lsx */
+/* including simdjson/generic/ondemand/json_type.h for lsx: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+/**
+ * The type of a JSON value.
+ */
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
+
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
 
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
-   *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
+   */
+  simdjson_inline bool is_uint64() const noexcept;
+  /**
+   * return the value as a uint64_t, only valid if is_uint64() is true.
+   */
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
 
-protected:
   /**
-   * Create a value.
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
    */
-  simdjson_inline value(const value_iterator &iter) noexcept;
-
+  simdjson_inline bool is_double() const noexcept;
   /**
-   * Skip this value, allowing iteration to continue.
+   * return the value as a double, only valid if is_double() is true.
    */
-  simdjson_inline void skip() noexcept;
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
   /**
-   * Start a value at the current position.
-   *
-   * (It should already be started; this is just a self-documentation method.)
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
    */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+  simdjson_inline double as_double() const noexcept;
+
 
+protected:
   /**
-   * Resume a value.
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
    */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
-
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
   /**
-   * Get the object, starting or resuming it as necessary
+   * End of friend declarations.
    */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
 
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
+  /**
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
+   */
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
+};
 
-  value_iterator iter{};
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
 
-  friend class document;
-  friend class array_iterator;
-  friend class field;
-  friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
-  friend class field;
-};
+#if SIMDJSON_EXCEPTIONS
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
+#endif
 
 } // namespace ondemand
 } // namespace lsx
@@ -104061,335 +107807,602 @@ class value {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::value> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value> {
+struct simdjson_result<lsx::ondemand::json_type> : public lsx::implementation_simdjson_result_base<lsx::ondemand::json_type> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::json_type &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
 
-  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() noexcept;
+} // namespace simdjson
 
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for lsx */
+/* including simdjson/generic/ondemand/raw_json_string.h for lsx: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
 
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lsx::ondemand::array() noexcept(false);
-  simdjson_inline operator lsx::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
+/**
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
+ *
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
+ *
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
+ *
+ */
+class raw_json_string {
+public:
+  /**
+   * Create a new invalid raw_json_string.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * Look up a field by name on an object (order-sensitive).
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   * The given location must be just *after* the beginning quote (") in the JSON file.
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
+   * It *must* be terminated by a ", and be a valid JSON string.
+   */
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  /**
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
+   */
+  simdjson_inline const char * raw() const noexcept;
+
+  /**
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
+   *
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) noexcept;
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
 
   /**
-   * Look up a field by name on an object, without regard to key order.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
+   */
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+
+  /**
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
+   *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<lsx::ondemand::value> operator[](int) noexcept = delete;
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
 
   /**
-   * Get the type of this JSON value.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   */
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+
+  /**
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   */
+  simdjson_inline bool is_equal(const char* target) const noexcept;
+
+  /**
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
+   */
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
+
+private:
+
+
+  /**
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
+   */
+  simdjson_inline void consume() noexcept { buf = nullptr; }
+
+  /**
+   * Checks whether the inner pointer is non-null and thus usable.
+   */
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
-
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   */
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
+  friend class object;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
 };
 
-} // namespace simdjson
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for lsx */
-/* including simdjson/generic/ondemand/logger.h for lsx: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
 namespace simdjson {
-namespace lsx {
-namespace ondemand {
 
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
+template<>
+struct simdjson_result<lsx::ondemand::raw_json_string> : public lsx::implementation_simdjson_result_base<lsx::ondemand::raw_json_string> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept;
 };
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
-#endif
-
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
-
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
-
-} // namespace logger
-} // namespace ondemand
-} // namespace lsx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for lsx */
-/* including simdjson/generic/ondemand/token_iterator.h for lsx: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for lsx */
+/* including simdjson/generic/ondemand/parser.h for lsx: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
+ */
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
  *
- * @private This is not intended for external use.
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
  */
-class token_iterator {
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
 public:
   /**
-   * Create a new invalid token_iterator.
+   * Create a JSON parser.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * The new parser will have zero capacity.
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
   /**
-   * Advance to the next token (returning the current one).
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
-  /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
-   */
-  simdjson_inline uint32_t current_offset() const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   * Start iterating an on-demand JSON document.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
-   */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for a given token.
+   * ### IMPORTANT: Validate what you use
    *
-   * The length will include any whitespace at the end of the token.
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * ### IMPORTANT: Buffer Lifetime
+   *
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
+   *
+   * ### IMPORTANT: Document Lifetime
+   *
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
 
   /**
-   * Get the JSON text for a given token.
+   * @private
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Start iterating an on-demand JSON document.
    *
-   * @param position The position of the token.
+   *   ondemand::parser parser;
+   *   json_iterator doc = parser.iterate(json);
+   *
+   * ### IMPORTANT: Buffer Lifetime
+   *
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
+   *
+   * ### IMPORTANT: Document Lifetime
+   *
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
+   *
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
+   * @param json The JSON to parse.
+   *
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * Parse a buffer containing many JSON documents.
    *
-   * The length will include any whitespace at the end of the token.
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
    *
-   * @param position The position of the token.
+   * No copy of the input buffer is made.
+   *
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   *
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
+   *
+   * ### Format
+   *
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
+   *
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
+   *
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
+   *
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * ### Threads
+   *
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
+   *
+   * ### Parser Capacity
+   *
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
+   *
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Get the maximum length of the JSON text for a root token.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   */
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+
+  /**
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
    *
-   * The length will include any whitespace at the end of the token.
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    *
-   * @param position The position of the token (start of the document).
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * Return the current index.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  simdjson_inline token_position position() const noexcept;
+  bool threaded{true};
+  #else
   /**
-   * Reset to a previously saved index.
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
-
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
-
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
-
-protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
-
+  bool threaded{false};
+  #endif
   /**
-   * Get the index of the JSON text for a given token (relative).
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
+
   /**
-   * Get the index of the JSON text for a given token.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * @param position The position of the token.
+   * ## IMPORTANT: string_view lifetime
    *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
 
-  const uint8_t *buf{};
-  token_position _position{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  /**
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
+   */
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
+#endif
+
+private:
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  std::unique_ptr<token_position[]> start_positions{};
+#endif
 
   friend class json_iterator;
-  friend class value_iterator;
-  friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+  friend class document_stream;
 };
 
 } // namespace ondemand
@@ -104399,27 +108412,28 @@ class token_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::token_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::token_iterator> {
+struct simdjson_result<lsx::ondemand::parser> : public lsx::implementation_simdjson_result_base<lsx::ondemand::parser> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::parser &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for lsx */
-/* including simdjson/generic/ondemand/json_iterator.h for lsx: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for lsx */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for lsx: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -104427,311 +108441,180 @@ namespace lsx {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
- *
- * @private This is not intended for external use.
+ * A forward-only JSON array.
  */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
-  /**
-   * Next free location in the string buffer.
-   *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
-   */
-  uint8_t *_string_buf_loc{};
-  /**
-   * JSON error, if there is one.
-   *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
-   *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
-   */
-  error_code error{SUCCESS};
-  /**
-   * Depth of the current token in the JSON.
-   *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
-   */
-  bool _streaming{false};
-
+class array {
 public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
-
-  /**
-   * Tell whether the iterator is still at the start
-   */
-  simdjson_inline bool at_root() const noexcept;
-
-  /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
-   */
-  simdjson_inline bool streaming() const noexcept;
-
-  /**
-   * Get the root value iterator
-   */
-  simdjson_inline token_position root_position() const noexcept;
-  /**
-   * Assert that we are at the document depth (== 1)
-   */
-  simdjson_inline void assert_at_document_depth() const noexcept;
-  /**
-   * Assert that we are at the root of the document
-   */
-  simdjson_inline void assert_at_root() const noexcept;
-
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
-
-  /**
-   * Tell whether the iterator is live (has not been moved).
-   */
-  simdjson_inline bool is_alive() const noexcept;
-
-  /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
-   */
-  simdjson_inline void abandon() noexcept;
-
-  /**
-   * Advance the current token without modifying depth.
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
-
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Create a new invalid array.
    *
-   * @return whether there is a single token
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline bool is_single_token() const noexcept;
+  simdjson_inline array() noexcept = default;
 
   /**
-   * Assert that there are at least the given number of tokens left.
-   *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
-  /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * Begin array iteration.
    *
-   * Has no effect in release builds.
+   * Part of the std::iterable interface.
    */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
   /**
-   * Get the JSON text for a given token (relative).
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Sentinel representing the end of the array.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * Part of the std::iterable interface.
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
-   *
-   * The length will include any whitespace at the end of the token.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Get a pointer to the current location in the input buffer.
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
   /**
-   * Get the JSON text for a given token.
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param position The position of the token to retrieve.
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns true if the array contains some elements (not empty)
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
-   *
-   * The length will include any whitespace at the end of the token.
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current root token.
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
    *
-   * The length will include any whitespace at the end of the token.
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
-  /**
-   * Get the JSON text for the last token in the document.
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
-   * Ascend one level.
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
    *
-   * Validates that the depth - 1 == parent_depth.
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
    *
-   * @param parent_depth the expected parent depth.
-   */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Descend one level.
-   *
-   * Validates that the new depth == child_depth.
-   *
-   * @param child_depth the expected child depth.
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
   /**
-   * Get current depth.
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline depth_t depth() const noexcept;
-
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+protected:
   /**
-   * Get current (writeable) location in the string buffer.
+   * Go to the end of the array, no matter where you are right now.
    */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline error_code consume() noexcept;
 
   /**
-   * Report an unrecoverable error, preventing further iteration.
+   * Begin array iteration.
    *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
-  /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
    */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
-
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
   /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
+   * Begin array iteration from the root.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
    */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
-
-  simdjson_inline token_position position() const noexcept;
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
   /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
+   * Begin array iteration.
+   *
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
+   *
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
-
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
-
-  simdjson_inline error_code consume_character(char c) noexcept;
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
-#endif
-
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
 
   /**
-   * Returns the current location in the document if in bounds.
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
+   *
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
+  simdjson_inline array(const value_iterator &iter) noexcept;
 
   /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
-   */
-  inline void rewind() noexcept;
-  /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
+   * Iterator marking current position.
+   *
+   * iter.is_alive() == false indicates iteration is complete.
    */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
+  value_iterator iter{};
 
-  friend class document;
-  friend class document_stream;
-  friend class object;
-  friend class array;
   friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
+};
 
 } // namespace ondemand
 } // namespace lsx
@@ -104740,161 +108623,99 @@ class json_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::json_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::json_iterator> {
+struct simdjson_result<lsx::ondemand::array> : public lsx::implementation_simdjson_result_base<lsx::ondemand::array> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::json_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::array &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-
   simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for lsx */
-/* including simdjson/generic/ondemand/json_type.h for lsx: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for lsx */
+/* including simdjson/generic/ondemand/array_iterator.h for lsx: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
 /**
- * The type of a JSON value.
+ * A forward-only JSON array.
+ *
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
  */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
+class array_iterator {
+public:
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
 
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
- */
-struct number {
+  //
+  // Iterator interface
+  //
 
   /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+   * Get the current element.
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
-   */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
-   */
-  simdjson_inline bool is_uint64() const noexcept;
-  /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
-   */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
-   */
-  simdjson_inline bool is_int64() const noexcept;
-  /**
-   * return the value as a int64_t, only valid if is_int64() is true.
-   */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
-
-
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
-   */
-  simdjson_inline bool is_double() const noexcept;
-  /**
-   * return the value as a double, only valid if is_double() is true.
-   */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
-
-  /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Part of the std::iterator interface.
    */
-  simdjson_inline double as_double() const noexcept;
-
-
-protected:
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
   /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
+   * Check if we are at the end of the JSON.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are no more elements in the JSON array.
    */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
   /**
-   * End of friend declarations.
+   * Check if there are more elements in the JSON array.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are more elements in the JSON array.
    */
-
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
   /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
    */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
+  simdjson_inline array_iterator &operator++() noexcept;
 
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+private:
+  value_iterator iter{};
 
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
+};
 
 } // namespace ondemand
 } // namespace lsx
@@ -104903,729 +108724,725 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &t
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::json_type> : public lsx::implementation_simdjson_result_base<lsx::ondemand::json_type> {
+struct simdjson_result<lsx::ondemand::array_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::array_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  //
+  // Iterator interface
+  //
+
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<lsx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<lsx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &operator++() noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for lsx */
-/* including simdjson/generic/ondemand/raw_json_string.h for lsx: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for lsx */
+/* including simdjson/generic/ondemand/document.h for lsx: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
 /**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
+ * A JSON document. It holds a json_iterator instance.
  *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
+ * Used by tokens to get text, and string buffer location.
  *
+ * You must keep the document around during iteration.
  */
-class raw_json_string {
+class document {
 public:
   /**
-   * Create a new invalid raw_json_string.
+   * Create a new invalid document.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline raw_json_string() noexcept = default;
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
 
   /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
+   * Cast this JSON value to an array.
    *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  /**
+   * Cast this JSON value to an object.
    *
-   * It *must* be terminated by a ", and be a valid JSON string.
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
   /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
+   * Cast this JSON value to an unsigned integer.
    *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline const char * raw() const noexcept;
-
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
+   * Cast this JSON value (inside string) to an unsigned integer.
    *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Cast this JSON value (inside string) to a double.
    *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  /**
+   * Cast this JSON value to a string.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * The string is guaranteed to be valid UTF-8.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * Important: Calling get_string() twice on the same document is an error.
+   *
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
-
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * The string is guaranteed to be valid UTF-8.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
-
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Cast this JSON value to a string.
+   *
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
-
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
-
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
-
-private:
-
-
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
   /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
    */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
+  simdjson_inline simdjson_result<value> get_value() noexcept;
 
   /**
-   * Checks whether the inner pointer is non-null and thus usable.
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
+   *
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
    */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
+   * Get this value as the given type.
    *
-   * ## IMPORTANT: string_view lifetime
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
-
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
    *
-   * ## IMPORTANT: string_view lifetime
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
-};
-
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
-
-/**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
- */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
-
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::raw_json_string> : public lsx::implementation_simdjson_result_base<lsx::ondemand::raw_json_string> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for lsx */
-/* including simdjson/generic/ondemand/parser.h for lsx: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <memory>
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-/**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
- *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
-/**
- * A JSON fragment iterator.
- *
- * This holds the actual iterator as well as the buffer for writing strings.
- */
-class parser {
-public:
   /**
-   * Create a JSON parser.
+   * Get this value as the given type.
    *
-   * The new parser will have zero capacity.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
-
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
+   *
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
 
   /**
-   * Start iterating an on-demand JSON document.
+   * Cast this JSON value to an array.
    *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() & noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() & noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
    *
-   * ### IMPORTANT: Validate what you use
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
    *
-   * ### IMPORTANT: Buffer Lifetime
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * ### IMPORTANT: Document Lifetime
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * ### REQUIRED: Buffer Padding
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
    *
-   * ### std::string references
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
    *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline operator value() noexcept(false);
+#endif
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  /**
+   * Begin array iteration.
    *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
    *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * Part of the std::iterable interface.
    */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
 
   /**
-   * @private
-   *
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * ### IMPORTANT: Document Lifetime
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
    *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   * ### REQUIRED: Buffer Padding
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * @param json The JSON to parse.
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * is an error.
    *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
-
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
 
   /**
-   * Parse a buffer containing many JSON documents.
-   *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
-   *
-   * No copy of the input buffer is made.
-   *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
-   *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
-   *
-   * ### Format
-   *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
-   *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
-   *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
-   *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
-   *
-   * ### REQUIRED: Buffer Padding
+   * Look up a field by name on an object, without regard to key order.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * ### Threads
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
    *
-   * ### Parser Capacity
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
    *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
   /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
-   *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
 
-  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  bool threaded{true};
-  #else
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid as long as the bytes in dst.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * @returns true if the number if negative.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
-
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
    *
-   * ## IMPORTANT: string_view lifetime
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
-   */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
-
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
-
-  friend class json_iterator;
-  friend class document_stream;
-};
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::parser> : public lsx::implementation_simdjson_result_base<lsx::ondemand::parser> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::parser &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for lsx */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for lsx: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
-/**
- * A forward-only JSON array.
- */
-class array {
-public:
   /**
-   * Create a new invalid array.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
    */
-  simdjson_inline array() noexcept = default;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
   /**
-   * Begin array iteration.
+   * Get the raw JSON for this token.
    *
-   * Part of the std::iterable interface.
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
    */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
   /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
    */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  inline void rewind() noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * Returns debugging information.
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  inline std::string to_debug_string() noexcept;
   /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
    */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  inline bool is_alive() noexcept;
+
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
    *
-   * @returns true if the array contains some elements (not empty)
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+
   /**
    * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
    *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
    *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
+   *   doc.at_pointer("/foo/a/1") == 20
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
+   * It is allowed for a key to be the empty string:
    *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
@@ -105634,397 +109451,92 @@ class array {
    *
    * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
    *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 protected:
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * Consumes the document.
    */
   simdjson_inline error_code consume() noexcept;
 
-  /**
-   * Begin array iteration.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
-  /**
-   * Begin array iteration from the root.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
-   */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
-  /**
-   * Begin array iteration.
-   *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
-   *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
-   */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
-
-  /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
-   *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
-   */
-  simdjson_inline array(const value_iterator &iter) noexcept;
-
-  /**
-   * Iterator marking current position.
-   *
-   * iter.is_alive() == false indicates iteration is complete.
-   */
-  value_iterator iter{};
-
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
-  friend class array_iterator;
-};
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::array> : public lsx::implementation_simdjson_result_base<lsx::ondemand::array> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::array &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for lsx */
-/* including simdjson/generic/ondemand/array_iterator.h for lsx: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
 
-/**
- * A forward-only JSON array.
- *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
- */
-class array_iterator {
-public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
 
   //
-  // Iterator interface
+  // Fields
   //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
 
-  /**
-   * Get the current element.
-   *
-   * Part of the std::iterator interface.
-   */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  /**
-   * Check if we are at the end of the JSON.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are no more elements in the JSON array.
-   */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
-  /**
-   * Check if there are more elements in the JSON array.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are more elements in the JSON array.
-   */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
-  /**
-   * Move to the next element.
-   *
-   * Part of the std::iterator interface.
-   */
-  simdjson_inline array_iterator &operator++() noexcept;
-
-private:
-  value_iterator iter{};
-
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
-
-  friend class array;
+  friend class array_iterator;
   friend class value;
-  friend struct simdjson_result<array_iterator>;
-};
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::array_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::array_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<lsx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<lsx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &operator++() noexcept;
+  friend class ondemand::parser;
+  friend class object;
+  friend class array;
+  friend class field;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
 };
 
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for lsx */
-/* including simdjson/generic/ondemand/document.h for lsx: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
- *
- * Used by tokens to get text, and string buffer location.
- *
- * You must keep the document around during iteration.
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
-class document {
+class document_reference {
 public:
-  /**
-   * Create a new invalid document.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
   simdjson_inline simdjson_result<array> get_array() & noexcept;
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
   simdjson_inline simdjson_result<object> get_object() & noexcept;
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: Calling get_string() twice on the same document is an error.
-   *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
   simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
   simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
-  /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
   template <typename T>
   simdjson_inline simdjson_result<T> get() &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -106038,16 +109550,6 @@ class document {
     SIMDJSON_TRY(get<T>(out));
     return out;
   }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
   template<typename T>
   simdjson_inline simdjson_result<T> get() &&
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -106056,7 +109558,7 @@ class document {
     noexcept
 #endif
   {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
       return static_cast<document&>(*this).get<T>();
   }
 
@@ -106074,13 +109576,13 @@ class document {
   template<typename T>
   simdjson_inline error_code get(T &out) &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
 #else
     noexcept
 #endif
   {
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
+    if constexpr (custom_deserializable<T, document_reference>) {
         return deserialize(*this, out);
     } else {
 #endif // SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -106098,146 +109600,697 @@ class document {
 #endif
   }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+private:
+  document *doc{nullptr};
+};
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lsx::ondemand::document> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lsx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lsx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lsx::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lsx::ondemand::document_reference> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document_reference> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lsx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lsx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lsx::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+/* end file simdjson/generic/ondemand/document.h for lsx */
+/* including simdjson/generic/ondemand/document_stream.h for lsx: #include "simdjson/generic/ondemand/document_stream.h" */
+/* begin file simdjson/generic/ondemand/document_stream.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+/** @private Custom worker class **/
+struct stage1_worker {
+  stage1_worker() noexcept = default;
+  stage1_worker(const stage1_worker&) = delete;
+  stage1_worker(stage1_worker&&) = delete;
+  stage1_worker operator=(const stage1_worker&) = delete;
+  ~stage1_worker();
+  /**
+   * We only start the thread when it is needed, not at object construction, this may throw.
+   * You should only call this once.
+   **/
+  void start_thread();
+  /**
+   * Start a stage 1 job. You should first call 'run', then 'finish'.
+   * You must call start_thread once before.
+   */
+  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
+  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
+  void finish();
+
+private:
+
+  /**
+   * Normally, we would never stop the thread. But we do in the destructor.
+   * This function is only safe assuming that you are not waiting for results. You
+   * should have called run, then finish, and be done.
+   **/
+  void stop_thread();
+
+  std::thread thread{};
+  /** These three variables define the work done by the thread. **/
+  ondemand::parser * stage1_thread_parser{};
+  size_t _next_batch_start{};
+  document_stream * owner{};
+  /**
+   * We have two state variables. This could be streamlined to one variable in the future but
+   * we use two for clarity.
+   */
+  bool has_work{false};
+  bool can_work{true};
+
+  /**
+   * We lock using a mutex.
+   */
+  std::mutex locking_mutex{};
+  std::condition_variable cond_var{};
+
+  friend class document_stream;
+};
+#endif  // SIMDJSON_THREADS_ENABLED
+
+/**
+ * A forward-only stream of documents.
+ *
+ * Produced by parser::iterate_many.
+ *
+ */
+class document_stream {
+public:
+  /**
+   * Construct an uninitialized document_stream.
+   *
+   *  ```c++
+   *  document_stream docs;
+   *  auto error = parser.iterate_many(json).get(docs);
+   *  ```
+   */
+  simdjson_inline document_stream() noexcept;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream(document_stream &&other) noexcept = default;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+
+  simdjson_inline ~document_stream() noexcept;
+
+  /**
+   * Returns the input size in bytes.
+   */
+  inline size_t size_in_bytes() const noexcept;
+
+  /**
+   * After iterating through the stream, this method
+   * returns the number of bytes that were not parsed at the end
+   * of the stream. If truncated_bytes() differs from zero,
+   * then the input was truncated maybe because incomplete JSON
+   * documents were found at the end of the stream. You
+   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   *
+   * You should only call truncated_bytes() after streaming through all
+   * documents, like so:
+   *
+   *   document_stream stream = parser.iterate_many(json,window);
+   *   for(auto & doc : stream) {
+   *      // do something with doc
+   *   }
+   *   size_t truncated = stream.truncated_bytes();
+   *
+   */
+  inline size_t truncated_bytes() const noexcept;
+
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
+
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
+
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
+
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
+
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
+
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
+
+  /**
+   * Start iterating the documents in the stream.
+   */
+  simdjson_inline iterator begin() noexcept;
+  /**
+   * The end of the stream, for iterator comparison purposes.
+   */
+  simdjson_inline iterator end() noexcept;
+
+private:
+
+  document_stream &operator=(const document_stream &) = delete; // Disallow copying
+  document_stream(const document_stream &other) = delete; // Disallow copying
+
+  /**
+   * Construct a document_stream. Does not allocate or parse anything until the iterator is
+   * used.
+   *
+   * @param parser is a reference to the parser instance used to generate this document_stream
+   * @param buf is the raw byte buffer we need to process
+   * @param len is the length of the raw byte buffer in bytes
+   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   */
+  simdjson_inline document_stream(
+    ondemand::parser &parser,
+    const uint8_t *buf,
+    size_t len,
+    size_t batch_size,
+    bool allow_comma_separated
+  ) noexcept;
+
+  /**
+   * Parse the first document in the buffer. Used by begin(), to handle allocation and
+   * initialization.
+   */
+  inline void start() noexcept;
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
+   * Parse the next document found in the buffer previously given to document_stream.
    *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   * The content should be a valid JSON document encoded as UTF-8. If there is a
+   * UTF-8 BOM, the parser skips it.
    *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
-  template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
-
-  /**
-   * Cast this JSON value to an array.
+   * You do NOT need to pre-allocate a parser.  This function takes care of
+   * pre-allocating a capacity defined by the batch_size defined when creating the
+   * document_stream object.
    *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
+   * The function returns simdjson::EMPTY if there is no more data to be parsed.
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() & noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
+   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
+   * and indicates that the buffer has successfully been parsed to the end.
+   * Every document it contained has been parsed without error.
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * The function returns an error code from simdjson/simdjson.h in case of failure
+   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
+   * the simdjson::error_message function converts these error codes into a string).
+   *
+   * You can also check validity by calling parser.is_valid(). The same parser can
+   * and should be reused for the other documents in the buffer.
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  inline void next() noexcept;
+
+  /** Move the json_iterator of the document to the location of the next document in the stream. */
+  inline void next_document() noexcept;
+
+  /** Get the next document index. */
+  inline size_t next_batch_start() const noexcept;
+
+  /** Pass the next batch through stage 1 with the given parser. */
+  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+
+  // Fields
+  ondemand::parser *parser;
+  const uint8_t *buf;
+  size_t len;
+  size_t batch_size;
+  bool allow_comma_separated;
   /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   * We are going to use just one document instance. The document owns
+   * the json_iterator. It implies that we only ever pass a reference
+   * to the document to the users.
    */
-  simdjson_inline operator int64_t() noexcept(false);
+  document doc{};
+  /** The error (or lack thereof) from the current document. */
+  error_code error;
+  size_t batch_start{0};
+  size_t doc_index{};
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
+  bool use_thread;
+
+  inline void load_from_stage1_thread() noexcept;
+
+  /** Start a thread to run stage 1 on the next batch. */
+  inline void start_stage1_thread() noexcept;
+
+  /** Wait for the stage 1 thread to finish and capture the results. */
+  inline void finish_stage1_thread() noexcept;
+
+  /** The error returned from the stage 1 thread. */
+  error_code stage1_thread_error{UNINITIALIZED};
+  /** The thread used to run stage 1 against the next batch in the background. */
+  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
   /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * The parser used to run stage 1 in the background. Will be swapped
+   * with the regular parser when finished.
    */
-  simdjson_inline operator double() noexcept(false);
+  ondemand::parser stage1_thread_parser{};
+
+  friend struct stage1_worker;
+  #endif // SIMDJSON_THREADS_ENABLED
+
+  friend class parser;
+  friend class document;
+  friend class json_iterator;
+  friend struct simdjson_result<ondemand::document_stream>;
+  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
+};  // document_stream
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+template<>
+struct simdjson_result<lsx::ondemand::document_stream> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document_stream> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::document_stream &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+/* end file simdjson/generic/ondemand/document_stream.h for lsx */
+/* including simdjson/generic/ondemand/field.h for lsx: #include "simdjson/generic/ondemand/field.h" */
+/* begin file simdjson/generic/ondemand/field.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+/**
+ * A JSON field (key/value pair) in an object.
+ *
+ * Returned from object iteration.
+ *
+ * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
+ */
+class field : public std::pair<raw_json_string, value> {
+public:
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * Create a new invalid field.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline field() noexcept;
+
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
   /**
-   * Cast this JSON value to a bool.
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it. The content is stored in the receiver.
    *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline operator bool() noexcept(false);
+  template <typename string_type>
+  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * Get the key as a raw_json_string. Can be used for direct comparison with
+   * an unescaped C string: e.g., key() == "test". This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key() for a similar function which returns
+   * a more convenient std::string_view result.
    */
-  simdjson_inline operator value() noexcept(false);
-#endif
+  simdjson_inline raw_json_string key() const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
+  simdjson_inline std::string_view key_raw_json_token() const noexcept;
+  /**
+   * Get the key as a string_view. This does not include the quotes and
+   * the string is unprocessed key so it may contain escape characters
+   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
+   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
    */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline std::string_view escaped_key() const noexcept;
   /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Get the field value.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline ondemand::value &value() & noexcept;
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * @overload ondemand::value &ondemand::value() & noexcept
    */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline ondemand::value value() && noexcept;
+
+protected:
+  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
+  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
+  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
+  friend struct simdjson_result<field>;
+  friend class object_iterator;
+};
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lsx::ondemand::field> : public lsx::implementation_simdjson_result_base<lsx::ondemand::field> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::field &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  template<typename string_type>
+  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> value() noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+/* end file simdjson/generic/ondemand/field.h for lsx */
+/* including simdjson/generic/ondemand/object.h for lsx: #include "simdjson/generic/ondemand/object.h" */
+/* begin file simdjson/generic/ondemand/object.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+/**
+ * A forward-only JSON object field iterator.
+ */
+class object {
+public:
   /**
-   * Sentinel representing the end of the array.
+   * Create a new invalid object.
    *
-   * Part of the std::iterable interface.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline object() noexcept = default;
 
+  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<object_iterator> end() noexcept;
   /**
    * Look up a field by name on an object (order-sensitive).
    *
@@ -106251,28 +110304,32 @@ class document {
    * double y = obj.find_field("y");
    * double x = obj.find_field("x");
    * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
    * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
    * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   *
    * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
    * given by content["bids"].get_array() should not be accessed after you have called
    * content["asks"].get_array(). You can detect such mistakes by first compiling and running
    * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
    * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * You are expected to access keys only once. You should access the value corresponding to a
+   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
    * is an error.
    *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
   simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
 
   /**
    * Look up a field by name on an object, without regard to key order.
@@ -106288,197 +110345,39 @@ class document {
    * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
    * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
+   * field was not there when they are not in order).
    *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
+   * Get the value associated with the given JSON pointer. We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
    *   ondemand::parser parser;
    *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
@@ -106492,233 +110391,103 @@ class document {
    *   auto doc = parser.iterate(json);
    *   doc.at_pointer("//a/1") == 20
    *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
+   * instance: there is no rewind and no invalidation.
    *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
    * JSONPath queries that trivially convertible to JSON Pointer queries: key
    * names and array indices.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
-   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the object. You should still consume values only once even if you
+   * can iterate through the object more than once. If you unescape a string or a key
+   * within the object more than once, you have unsafe code. Note that rewinding an object
+   * means that you may need to reparse it anew: it is not a free operation.
+   *
+   * @returns true if the object contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * This method scans the beginning of the object and checks whether the
+   * object is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Consumes the object and returns a string_view instance corresponding to the
+   * object as represented in JSON. It points inside the original byte array containing
    * the JSON document.
    */
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 protected:
   /**
-   * Consumes the document.
+   * Go to the end of the object, no matter where you are right now.
    */
   simdjson_inline error_code consume() noexcept;
+  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
+  static simdjson_inline object resume(const value_iterator &iter) noexcept;
+  simdjson_inline object(const value_iterator &iter) noexcept;
 
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
+  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
 
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+  value_iterator iter{};
 
-  friend class array_iterator;
   friend class value;
-  friend class ondemand::parser;
-  friend class object;
-  friend class array;
-  friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
+  friend class document;
+  friend struct simdjson_result<object>;
 };
 
-
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-private:
-  document *doc{nullptr};
-};
 } // namespace ondemand
 } // namespace lsx
 } // namespace simdjson
@@ -106726,840 +110495,675 @@ class document_reference {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lsx::ondemand::document> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document> {
+struct simdjson_result<lsx::ondemand::object> : public lsx::implementation_simdjson_result_base<lsx::ondemand::object> {
 public:
-  simdjson_inline simdjson_result(lsx::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lsx::ondemand::object &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
 
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lsx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lsx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lsx::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> end() noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool at_end() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
+  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) && noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
   simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
-
-
-} // namespace simdjson
-
-
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::document_reference> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document_reference> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::document_reference value, error_code error) noexcept;
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lsx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
 
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lsx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lsx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lsx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lsx::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lsx::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lsx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  inline simdjson_result<bool> reset() noexcept;
+  inline simdjson_result<bool> is_empty() noexcept;
+  inline simdjson_result<size_t> count_fields() & noexcept;
+  inline simdjson_result<std::string_view> raw_json() noexcept;
 
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
 };
 
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-/* end file simdjson/generic/ondemand/document.h for lsx */
-/* including simdjson/generic/ondemand/document_stream.h for lsx: #include "simdjson/generic/ondemand/document_stream.h" */
-/* begin file simdjson/generic/ondemand/document_stream.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+/* end file simdjson/generic/ondemand/object.h for lsx */
+/* including simdjson/generic/ondemand/object_iterator.h for lsx: #include "simdjson/generic/ondemand/object_iterator.h" */
+/* begin file simdjson/generic/ondemand/object_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-#ifdef SIMDJSON_THREADS_ENABLED
-/** @private Custom worker class **/
-struct stage1_worker {
-  stage1_worker() noexcept = default;
-  stage1_worker(const stage1_worker&) = delete;
-  stage1_worker(stage1_worker&&) = delete;
-  stage1_worker operator=(const stage1_worker&) = delete;
-  ~stage1_worker();
-  /**
-   * We only start the thread when it is needed, not at object construction, this may throw.
-   * You should only call this once.
-   **/
-  void start_thread();
-  /**
-   * Start a stage 1 job. You should first call 'run', then 'finish'.
-   * You must call start_thread once before.
-   */
-  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
-  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
-  void finish();
-
-private:
-
-  /**
-   * Normally, we would never stop the thread. But we do in the destructor.
-   * This function is only safe assuming that you are not waiting for results. You
-   * should have called run, then finish, and be done.
-   **/
-  void stop_thread();
-
-  std::thread thread{};
-  /** These three variables define the work done by the thread. **/
-  ondemand::parser * stage1_thread_parser{};
-  size_t _next_batch_start{};
-  document_stream * owner{};
-  /**
-   * We have two state variables. This could be streamlined to one variable in the future but
-   * we use two for clarity.
-   */
-  bool has_work{false};
-  bool can_work{true};
-
-  /**
-   * We lock using a mutex.
-   */
-  std::mutex locking_mutex{};
-  std::condition_variable cond_var{};
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  friend class document_stream;
-};
-#endif  // SIMDJSON_THREADS_ENABLED
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-/**
- * A forward-only stream of documents.
- *
- * Produced by parser::iterate_many.
- *
- */
-class document_stream {
+class object_iterator {
 public:
   /**
-   * Construct an uninitialized document_stream.
+   * Create a new invalid object_iterator.
    *
-   *  ```c++
-   *  document_stream docs;
-   *  auto error = parser.iterate_many(json).get(docs);
-   *  ```
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline document_stream() noexcept;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream(document_stream &&other) noexcept = default;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+  simdjson_inline object_iterator() noexcept = default;
 
-  simdjson_inline ~document_stream() noexcept;
+  //
+  // Iterator interface
+  //
 
-  /**
-   * Returns the input size in bytes.
-   */
-  inline size_t size_in_bytes() const noexcept;
+  // Reads key and value, yielding them to the user.
+  // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline simdjson_result<field> operator*() noexcept;
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const object_iterator &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline object_iterator &operator++() noexcept;
 
+private:
   /**
-   * After iterating through the stream, this method
-   * returns the number of bytes that were not parsed at the end
-   * of the stream. If truncated_bytes() differs from zero,
-   * then the input was truncated maybe because incomplete JSON
-   * documents were found at the end of the stream. You
-   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
-   *
-   * You should only call truncated_bytes() after streaming through all
-   * documents, like so:
-   *
-   *   document_stream stream = parser.iterate_many(json,window);
-   *   for(auto & doc : stream) {
-   *      // do something with doc
-   *   }
-   *   size_t truncated = stream.truncated_bytes();
+   * The underlying JSON iterator.
    *
+   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
+   * is first used, and never changes afterwards.
    */
-  inline size_t truncated_bytes() const noexcept;
+  value_iterator iter{};
 
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
+  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
+  friend struct simdjson_result<object_iterator>;
+  friend class object;
+};
 
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
+namespace simdjson {
 
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
+template<>
+struct simdjson_result<lsx::ondemand::object_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::object_iterator> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::object_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
+  //
+  // Iterator interface
+  //
 
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
+  // Reads key and value, yielding them to the user.
+  simdjson_inline simdjson_result<lsx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const simdjson_result<lsx::ondemand::object_iterator> &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const simdjson_result<lsx::ondemand::object_iterator> &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &operator++() noexcept;
+};
 
-  /**
-   * Start iterating the documents in the stream.
-   */
-  simdjson_inline iterator begin() noexcept;
-  /**
-   * The end of the stream, for iterator comparison purposes.
-   */
-  simdjson_inline iterator end() noexcept;
+} // namespace simdjson
 
-private:
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+/* end file simdjson/generic/ondemand/object_iterator.h for lsx */
+/* including simdjson/generic/ondemand/serialization.h for lsx: #include "simdjson/generic/ondemand/serialization.h" */
+/* begin file simdjson/generic/ondemand/serialization.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 
-  document_stream &operator=(const document_stream &) = delete; // Disallow copying
-  document_stream(const document_stream &other) = delete; // Disallow copying
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Construct a document_stream. Does not allocate or parse anything until the iterator is
-   * used.
-   *
-   * @param parser is a reference to the parser instance used to generate this document_stream
-   * @param buf is the raw byte buffer we need to process
-   * @param len is the length of the raw byte buffer in bytes
-   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
-   */
-  simdjson_inline document_stream(
-    ondemand::parser &parser,
-    const uint8_t *buf,
-    size_t len,
-    size_t batch_size,
-    bool allow_comma_separated
-  ) noexcept;
+namespace simdjson {
+/**
+ * Create a string-view instance out of a document instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept;
+/**
+ * Create a string-view instance out of a value instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. The value must
+ * not have been accessed previously. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept;
+/**
+ * Create a string-view instance out of an object instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept;
+/**
+ * Create a string-view instance out of an array instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x);
+} // namespace simdjson
 
-  /**
-   * Parse the first document in the buffer. Used by begin(), to handle allocation and
-   * initialization.
-   */
-  inline void start() noexcept;
+/**
+ * We want to support argument-dependent lookup (ADL).
+ * Hence we should define operator<< in the namespace
+ * where the argument (here value, object, etc.) resides.
+ * Credit: @madhur4127
+ * See https://github.com/simdjson/simdjson/issues/1768
+ */
+namespace simdjson { namespace lsx { namespace ondemand {
 
-  /**
-   * Parse the next document found in the buffer previously given to document_stream.
-   *
-   * The content should be a valid JSON document encoded as UTF-8. If there is a
-   * UTF-8 BOM, the parser skips it.
-   *
-   * You do NOT need to pre-allocate a parser.  This function takes care of
-   * pre-allocating a capacity defined by the batch_size defined when creating the
-   * document_stream object.
-   *
-   * The function returns simdjson::EMPTY if there is no more data to be parsed.
-   *
-   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
-   * and indicates that the buffer has successfully been parsed to the end.
-   * Every document it contained has been parsed without error.
-   *
-   * The function returns an error code from simdjson/simdjson.h in case of failure
-   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
-   * the simdjson::error_message function converts these error codes into a string).
-   *
-   * You can also check validity by calling parser.is_valid(). The same parser can
-   * and should be reused for the other documents in the buffer.
-   */
-  inline void next() noexcept;
+/**
+ * Print JSON to an output stream.  It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The element.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x);
+#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The object.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::object> x);
+#endif
+}}} // namespace simdjson::lsx::ondemand
 
-  /** Move the json_iterator of the document to the location of the next document in the stream. */
-  inline void next_document() noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+/* end file simdjson/generic/ondemand/serialization.h for lsx */
 
-  /** Get the next document index. */
-  inline size_t next_batch_start() const noexcept;
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for lsx: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for lsx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
-  /** Pass the next batch through stage 1 with the given parser. */
-  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // Fields
-  ondemand::parser *parser;
-  const uint8_t *buf;
-  size_t len;
-  size_t batch_size;
-  bool allow_comma_separated;
-  /**
-   * We are going to use just one document instance. The document owns
-   * the json_iterator. It implies that we only ever pass a reference
-   * to the document to the users.
-   */
-  document doc{};
-  /** The error (or lack thereof) from the current document. */
-  error_code error;
-  size_t batch_start{0};
-  size_t doc_index{};
+#include <concepts>
+#include <limits>
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
-  bool use_thread;
+namespace simdjson {
+template <typename T>
+constexpr bool require_custom_serialization = false;
 
-  inline void load_from_stage1_thread() noexcept;
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
 
-  /** Start a thread to run stage 1 on the next batch. */
-  inline void start_stage1_thread() noexcept;
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  /** Wait for the stage 1 thread to finish and capture the results. */
-  inline void finish_stage1_thread() noexcept;
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  /** The error returned from the stage 1 thread. */
-  error_code stage1_thread_error{UNINITIALIZED};
-  /** The thread used to run stage 1 against the next batch in the background. */
-  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
-  /**
-   * The parser used to run stage 1 in the background. Will be swapped
-   * with the regular parser when finished.
-   */
-  ondemand::parser stage1_thread_parser{};
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  friend struct stage1_worker;
-  #endif // SIMDJSON_THREADS_ENABLED
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  friend class parser;
-  friend class document;
-  friend class json_iterator;
-  friend struct simdjson_result<ondemand::document_stream>;
-  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
-};  // document_stream
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
+
+/**
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
+ */
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
+
+  lsx::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
+
+
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
+
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
+
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
+
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
 
-namespace simdjson {
-template<>
-struct simdjson_result<lsx::ondemand::document_stream> : public lsx::implementation_simdjson_result_base<lsx::ondemand::document_stream> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::document_stream &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
-/* end file simdjson/generic/ondemand/document_stream.h for lsx */
-/* including simdjson/generic/ondemand/field.h for lsx: #include "simdjson/generic/ondemand/field.h" */
-/* begin file simdjson/generic/ondemand/field.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for lsx */
+
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for lsx: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-/**
- * A JSON field (key/value pair) in an object.
- *
- * Returned from object iteration.
- *
- * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
- */
-class field : public std::pair<raw_json_string, value> {
-public:
-  /**
-   * Create a new invalid field.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline field() noexcept;
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the array is first found and the iterator is just past the `{`.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
+//   depth == iter->depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter->depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the array iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
+//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
+//
+// ## Terminal State
+//
+// The terminal state has iter->depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
+//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
+//   error == SUCCESS.
+//
 
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it. The content is stored in the receiver.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  template <typename string_type>
-  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a raw_json_string. Can be used for direct comparison with
-   * an unescaped C string: e.g., key() == "test". This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key() for a similar function which returns
-   * a more convenient std::string_view result.
-   */
-  simdjson_inline raw_json_string key() const noexcept;
-  /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
-   */
-  simdjson_inline std::string_view key_raw_json_token() const noexcept;
-  /**
-   * Get the key as a string_view. This does not include the quotes and
-   * the string is unprocessed key so it may contain escape characters
-   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
-   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
-   */
-  simdjson_inline std::string_view escaped_key() const noexcept;
-  /**
-   * Get the field value.
-   */
-  simdjson_inline ondemand::value &value() & noexcept;
-  /**
-   * @overload ondemand::value &ondemand::value() & noexcept
-   */
-  simdjson_inline ondemand::value value() && noexcept;
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
 
-protected:
-  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
-  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
-  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
-  friend struct simdjson_result<field>;
-  friend class object_iterator;
-};
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  bool has_value;
+  SIMDJSON_TRY(iter.started_array().get(has_value));
+  return array(iter);
+}
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
+simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return array_iterator(iter);
+}
+simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
+  return array_iterator(iter);
+}
+simdjson_inline error_code array::consume() noexcept {
+  auto error = iter.json_iter().skip_child(iter.depth()-1);
+  if(error) { iter.abandon(); }
+  return error;
+}
 
-namespace simdjson {
+simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-template<>
-struct simdjson_result<lsx::ondemand::field> : public lsx::implementation_simdjson_result_base<lsx::ondemand::field> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::field &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the array after counting the number of elements.
+  iter.reset_array();
+  return count;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  template<typename string_type>
-  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> key() noexcept;
-  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> value() noexcept;
-};
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
 
-} // namespace simdjson
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-/* end file simdjson/generic/ondemand/field.h for lsx */
-/* including simdjson/generic/ondemand/object.h for lsx: #include "simdjson/generic/ondemand/object.h" */
-/* begin file simdjson/generic/ondemand/object.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-/**
- * A forward-only JSON object field iterator.
- */
-class object {
-public:
-  /**
-   * Create a new invalid object.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object() noexcept = default;
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
 
-  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<object_iterator> end() noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a
-   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
 
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
 
-  /**
-   * Get the value associated with the given JSON pointer. We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
-   * instance: there is no rewind and no invalidation.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
 
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-  /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the object. You should still consume values only once even if you
-   * can iterate through the object more than once. If you unescape a string or a key
-   * within the object more than once, you have unsafe code. Note that rewinding an object
-   * means that you may need to reparse it anew: it is not a free operation.
-   *
-   * @returns true if the object contains some elements (not empty)
-   */
-  inline simdjson_result<bool> reset() & noexcept;
-  /**
-   * This method scans the beginning of the object and checks whether the
-   * object is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   */
-  inline simdjson_result<bool> is_empty() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Consumes the object and returns a string_view instance corresponding to the
-   * object as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
+  lsx::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::array>(
+      std::forward<lsx::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<lsx::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
+} // namespace simdjson
 
-protected:
-  /**
-   * Go to the end of the object, no matter where you are right now.
-   */
-  simdjson_inline error_code consume() noexcept;
-  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
-  static simdjson_inline object resume(const value_iterator &iter) noexcept;
-  simdjson_inline object(const value_iterator &iter) noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for lsx */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
 
-  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  value_iterator iter{};
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<object>;
-};
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
 
 } // namespace ondemand
 } // namespace lsx
@@ -107567,86 +111171,276 @@ class object {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<lsx::ondemand::object> : public lsx::implementation_simdjson_result_base<lsx::ondemand::object> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::object &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> end() noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> operator[](std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lsx::ondemand::value> at_path(std::string_view json_path) noexcept;
-
-  inline simdjson_result<bool> reset() noexcept;
-  inline simdjson_result<bool> is_empty() noexcept;
-  inline simdjson_result<size_t> count_fields() & noexcept;
-  inline simdjson_result<std::string_view> raw_json() noexcept;
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(
+  lsx::ondemand::array_iterator &&value
+) noexcept
+  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>(std::forward<lsx::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>({}, error)
+{
+}
 
-};
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator==(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator!=(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &simdjson_result<lsx::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
-/* end file simdjson/generic/ondemand/object.h for lsx */
-/* including simdjson/generic/ondemand/object_iterator.h for lsx: #include "simdjson/generic/ondemand/object_iterator.h" */
-/* begin file simdjson/generic/ondemand/object_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-class object_iterator {
-public:
-  /**
-   * Create a new invalid object_iterator.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object_iterator() noexcept = default;
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
 
-  //
-  // Iterator interface
-  //
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
 
-  // Reads key and value, yielding them to the user.
-  // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline simdjson_result<field> operator*() noexcept;
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const object_iterator &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline object_iterator &operator++() noexcept;
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
 
-private:
-  /**
-   * The underlying JSON iterator.
-   *
-   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
-   * is first used, and never changes afterwards.
-   */
-  value_iterator iter{};
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
-  friend struct simdjson_result<object_iterator>;
-  friend class object;
-};
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace lsx
@@ -107654,137 +111448,218 @@ class object_iterator {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<lsx::ondemand::object_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::object_iterator> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::object_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+  lsx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(
+      std::forward<lsx::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
 
-  //
-  // Iterator interface
-  //
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
 
-  // Reads key and value, yielding them to the user.
-  simdjson_inline simdjson_result<lsx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const simdjson_result<lsx::ondemand::object_iterator> &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const simdjson_result<lsx::ondemand::object_iterator> &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &operator++() noexcept;
-};
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
 
-} // namespace simdjson
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-/* end file simdjson/generic/ondemand/object_iterator.h for lsx */
-/* including simdjson/generic/ondemand/serialization.h for lsx: #include "simdjson/generic/ondemand/serialization.h" */
-/* begin file simdjson/generic/ondemand/serialization.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
 
-namespace simdjson {
-/**
- * Create a string-view instance out of a document instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept;
-/**
- * Create a string-view instance out of a value instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. The value must
- * not have been accessed previously. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept;
-/**
- * Create a string-view instance out of an object instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept;
-/**
- * Create a string-view instance out of an array instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept;
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x);
-} // namespace simdjson
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
 
-/**
- * We want to support argument-dependent lookup (ADL).
- * Hence we should define operator<< in the namespace
- * where the argument (here value, object, etc.) resides.
- * Credit: @madhur4127
- * See https://github.com/simdjson/simdjson/issues/1768
- */
-namespace simdjson { namespace lsx { namespace ondemand {
+template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-/**
- * Print JSON to an output stream.  It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The element.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x);
-#endif
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The object.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value);
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
 #if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::object> x);
+template <class T>
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
 #endif
-}}} // namespace simdjson::lsx::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-/* end file simdjson/generic/ondemand/serialization.h for lsx */
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
 
 // Deserialization for standard types
 /* including simdjson/generic/ondemand/std_deserialize.h for lsx: #include "simdjson/generic/ondemand/std_deserialize.h" */
@@ -107973,307 +111848,26 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the array is first found and the iterator is just past the `{`.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
-//   depth == iter->depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter->depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the array iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
-//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
-//
-// ## Terminal State
-//
-// The terminal state has iter->depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
-//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
-//   error == SUCCESS.
-//
-
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
-  bool has_value;
-  SIMDJSON_TRY(iter.started_array().get(has_value));
-  return array(iter);
-}
-
-simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return array_iterator(iter);
-}
-simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
-  return array_iterator(iter);
-}
-simdjson_inline error_code array::consume() noexcept {
-  auto error = iter.json_iter().skip_child(iter.depth()-1);
-  if(error) { iter.abandon(); }
-  return error;
-}
-
-simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the array after counting the number of elements.
-  iter.reset_array();
-  return count;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
-}
-
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
-
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
-
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
-
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
-
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
   }
-  return child;
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
   }
-  return INDEX_OUT_OF_BOUNDS;
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
-  lsx::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::array>(
-      std::forward<lsx::ondemand::array>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lsx::ondemand::array>::simdjson_result(
-  error_code error
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::array>(error)
-{
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::array>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::array>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline  simdjson_result<bool> simdjson_result<lsx::ondemand::array>::is_empty() & noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-simdjson_inline  simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
   return first.at_path(json_path);
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::array>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for lsx */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
-}
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
-}
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(
-  lsx::ondemand::array_iterator &&value
-) noexcept
-  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>(std::forward<lsx::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : lsx::implementation_simdjson_result_base<lsx::ondemand::array_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::array_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator==(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-simdjson_inline bool simdjson_result<lsx::ondemand::array_iterator>::operator!=(const simdjson_result<lsx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> &simdjson_result<lsx::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
-}
 
 } // namespace simdjson
 
@@ -109319,7 +112913,6 @@ simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondem
   return first.at_path(json_path);
 }
 
-} // namespace simdjson
 
 #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 /* end file simdjson/generic/ondemand/value-inl.h for lsx */
@@ -109343,9 +112936,23 @@ simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondem
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
   : iter{std::forward<json_iterator>(_iter)}
@@ -109680,168 +113287,801 @@ simdjson_inline simdjson_result<value> document::at_path(std::string_view json_p
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
-  lsx::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document>(
-      std::forward<lsx::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document>(
-      error
-    )
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_elements() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
+  lsx::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::document>(
+      std::forward<lsx::ondemand::document>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::document>(
+      error
+    )
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first).get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<lsx::ondemand::document>(first);
+  return SUCCESS;
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+
+simdjson_inline bool simdjson_result<lsx::ondemand::document>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first).get<T>();
+}
+
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+
+
+#if SIMDJSON_EXCEPTIONS
+template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document>::current_location() noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first);
+}
+
+simdjson_inline bool simdjson_result<lsx::ondemand::document>::at_end() const noexcept {
+  if (error()) { return error(); }
+  return first.at_end();
+}
+
+
+simdjson_inline int32_t simdjson_result<lsx::ondemand::document>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  out = std::forward<lsx::ondemand::document>(first);
+  return SUCCESS;
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+
+
+namespace simdjson {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::simdjson_result(lsx::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<lsx::ondemand::document_reference>(std::forward<lsx::ondemand::document_reference>(value), error) {}
+
+
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at(size_t index) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::rewind() noexcept {
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::rewind() noexcept {
   if (error()) { return error(); }
   first.rewind();
   return SUCCESS;
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::begin() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::begin() & noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::end() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::end() & noexcept {
   return {};
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](const char *key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(std::string_view key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(const char *key) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document>::get_array() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document_reference>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document>::get_object() & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document_reference>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document_reference>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::get_value() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::get_value() noexcept {
   if (error()) { return error(); }
   return first.get_value();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_null() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_null() noexcept {
   if (error()) { return error(); }
   return first.is_null();
 }
-
 template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() & noexcept {
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
 template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() && noexcept {
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() && noexcept {
   if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first).get<T>();
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) & noexcept {
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) && noexcept {
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first).get<T>(out);
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>(out);
 }
-
-template<> simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() && noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first);
+  return first.type();
 }
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) && noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_scalar() noexcept {
   if (error()) { return error(); }
-  out = std::forward<lsx::ondemand::document>(first);
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
   return SUCCESS;
 }
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, lsx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, lsx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document_reference>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
 
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document>::type() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return first.raw_json_token();
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_path(json_path);
+}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for lsx */
+/* including simdjson/generic/ondemand/document_stream-inl.h for lsx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
+}
+
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
+}
+
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
+}
+
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
+
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
+
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
+}
+
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
+}
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
+}
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
+}
+
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
+
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
+}
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
+}
+
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+}
+
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
 simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_scalar() noexcept {
@@ -111672,12 +115912,26 @@ namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   return value(iter.child());
 }
@@ -111700,49 +115954,37 @@ simdjson_inline simdjson_result<value> object::find_field(const std::string_view
   bool has_value;
   SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
   if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
-}
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
   }
   auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
   if(error_skip) { iter.abandon(); }
@@ -111762,8 +116004,19 @@ simdjson_inline simdjson_result<object> object::started(value_iterator &iter) no
   return object(iter);
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
 simdjson_inline object::object(const value_iterator &_iter) noexcept
@@ -112279,474 +116532,6 @@ simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_co
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-/* end file simdjson/generic/ondemand/parser-inl.h for lsx */
-/* including simdjson/generic/ondemand/raw_json_string-inl.h for lsx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
-  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
-  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
-  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters, and
-  // the raw content is quote terminated within a valid JSON string.
-  const char * r{raw()};
-  size_t pos{0};
-  bool escaping{false};
-  for(;target[pos];pos++) {
-    if(r[pos] != target[pos]) { return false; }
-    // if target is a compile-time constant and it is free from
-    // quotes, then the next part could get optimized away through
-    // inlining.
-    if((target[pos] == '"') && !escaping) {
-      // We have reached the end of the raw_json_string but
-      // the target is not done.
-      return false;
-    } else if(target[pos] == '\\') {
-      escaping = !escaping;
-    } else {
-      escaping = false;
-    }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
-  return a.unsafe_is_equal(c);
-}
-
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
-  return a == c;
-}
-
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
-  return !(a == c);
-}
-
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
-  return !(a == c);
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
-  lsx::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
 #endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 /* end file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
 /* including simdjson/generic/ondemand/value_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
@@ -112845,7 +116630,6 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
-} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -115514,32 +119298,405 @@ class value {
    * resort as it may require scanning the document twice or more.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
+
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
+
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
+  /**
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  /**
+   * Checks whether the value is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the value is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
+   */
+  simdjson_inline std::string_view raw_json_token() noexcept;
+
+  /**
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
+
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+
+
+protected:
+  /**
+   * Create a value.
+   */
+  simdjson_inline value(const value_iterator &iter) noexcept;
+
+  /**
+   * Skip this value, allowing iteration to continue.
+   */
+  simdjson_inline void skip() noexcept;
+
+  /**
+   * Start a value at the current position.
+   *
+   * (It should already be started; this is just a self-documentation method.)
+   */
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
+
+  /**
+   * Resume a value.
+   */
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
+
+  /**
+   * Get the object, starting or resuming it as necessary
+   */
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
+
+  value_iterator iter{};
+
+  friend class document;
+  friend class array_iterator;
+  friend class field;
+  friend class object;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
+  friend class field;
+};
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::value> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() noexcept;
+
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+
   /**
    * Look up a field by name on an object (order-sensitive).
    *
@@ -115553,18 +119710,16 @@ class value {
    * double y = obj.find_field("y");
    * double x = obj.find_field("x");
    * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
+   *
    * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
    * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) noexcept;
 
   /**
    * Look up a field by name on an object, without regard to key order.
@@ -115579,287 +119734,595 @@ class value {
    * default behavior failed to look up a field just because it was in the wrong order--and many
    * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
    * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
    * field as not there when they are not in order).
    *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) noexcept = delete;
 
   /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * Get the type of this JSON value.
    *
    * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
    * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
    * let it throw an exception).
-   *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for lasx */
+/* including simdjson/generic/ondemand/logger.h for lasx: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
+
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
+};
+
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
+#else
+  static constexpr const bool LOG_ENABLED = false;
+#endif
+
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+} // namespace logger
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for lasx */
+/* including simdjson/generic/ondemand/token_iterator.h for lasx: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
+ *
+ * @private This is not intended for external use.
+ */
+class token_iterator {
+public:
   /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   * Create a new invalid token_iterator.
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+
   /**
-   * Checks whether the value is a string.
+   * Advance to the next token (returning the current one).
+   */
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  /**
+   * Reports the current offset in bytes from the start of the underlying buffer.
+   */
+  simdjson_inline uint32_t current_offset() const noexcept;
+  /**
+   * Get the JSON text for a given token (relative).
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
    */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Checks whether the value is a negative number.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @returns true if the number if negative.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+
   /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
+   * Get the JSON text for a given token.
    *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
    *
-   * @returns true if the number if negative.
    */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
+   * The length will include any whitespace at the end of the token.
    *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   * @param position The position of the token.
+   */
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for a root token.
    *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
+   * The length will include any whitespace at the end of the token.
    *
-   * @returns the type of the number
+   * @param position The position of the token (start of the document).
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Return the current index.
+   */
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Reset to a previously saved index.
+   */
+  simdjson_inline void set_position(token_position target_position) noexcept;
+
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
+
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+
+protected:
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
 
   /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
+   * Get the index of the JSON text for a given token (relative).
    *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   */
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  /**
+   * Get the index of the JSON text for a given token.
    *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
+   * @param position The position of the token.
    *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+
+  const uint8_t *buf{};
+  token_position _position{};
+
+  friend class json_iterator;
+  friend class value_iterator;
+  friend class object;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+};
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::token_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::token_iterator> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for lasx */
+/* including simdjson/generic/ondemand/json_iterator.h for lasx: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
+ */
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
   /**
-   * Get the raw JSON for this token.
+   * Next free location in the string buffer.
    *
-   * The string_view will always point into the input buffer.
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
+   */
+  uint8_t *_string_buf_loc{};
+  /**
+   * JSON error, if there is one.
    *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
    *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
+   */
+  error_code error{SUCCESS};
+  /**
+   * Depth of the current token in the JSON.
    *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
+   */
+  depth_t _depth{};
+  /**
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
+   */
+  token_position _root{};
+  /**
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
+   */
+  bool _streaming{false};
+
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
+  /**
+   * Skips a JSON value, whether it is a scalar, array or object.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
+
+  /**
+   * Tell whether the iterator is still at the start
+   */
+  simdjson_inline bool at_root() const noexcept;
+
+  /**
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
+   */
+  simdjson_inline bool streaming() const noexcept;
+
+  /**
+   * Get the root value iterator
+   */
+  simdjson_inline token_position root_position() const noexcept;
+  /**
+   * Assert that we are at the document depth (== 1)
+   */
+  simdjson_inline void assert_at_document_depth() const noexcept;
+  /**
+   * Assert that we are at the root of the document
+   */
+  simdjson_inline void assert_at_root() const noexcept;
+
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
+
+  /**
+   * Tell whether the iterator is live (has not been moved).
+   */
+  simdjson_inline bool is_alive() const noexcept;
+
+  /**
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   */
+  simdjson_inline void abandon() noexcept;
+
+  /**
+   * Advance the current token without modifying depth.
+   */
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+
+  /**
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * See also value::raw_json().
+   * @return whether there is a single token
    */
-  simdjson_inline std::string_view raw_json_token() noexcept;
+  simdjson_inline bool is_single_token() const noexcept;
 
   /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
+   * Assert that there are at least the given number of tokens left.
+   *
+   * Has no effect in release builds.
+   */
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
+  /**
+   * Assert that the given position addresses an actual token (is within bounds).
+   *
+   * Has no effect in release builds.
+   */
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
+  /**
+   * Get the JSON text for a given token (relative).
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Returns the current location in the document if in bounds.
+   * Get the maximum length of the JSON text for the current token (or relative).
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * Returns the current depth in the document if in bounds.
+   * Get a pointer to the current location in the input buffer.
    *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
    */
-  simdjson_inline int32_t current_depth() const noexcept;
-
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
+   * Get the JSON text for a given token.
    *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * It is allowed for a key to be the empty string:
+   * @param position The position of the token to retrieve.
    *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
+   */
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
+   * The length will include any whitespace at the end of the token.
    *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
+   * @param position The position of the token to retrieve.
+   */
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for the current root token.
    *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
+   * The length will include any whitespace at the end of the token.
    *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   * @param position The position of the token to retrieve.
+   */
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Get the JSON text for the last token in the document.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * Ascend one level.
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   * Validates that the depth - 1 == parent_depth.
+   *
+   * @param parent_depth the expected parent depth.
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
 
+  /**
+   * Descend one level.
+   *
+   * Validates that the new depth == child_depth.
+   *
+   * @param child_depth the expected child depth.
+   */
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
 
-protected:
   /**
-   * Create a value.
+   * Get current depth.
    */
-  simdjson_inline value(const value_iterator &iter) noexcept;
+  simdjson_inline depth_t depth() const noexcept;
 
   /**
-   * Skip this value, allowing iteration to continue.
+   * Get current (writeable) location in the string buffer.
    */
-  simdjson_inline void skip() noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
   /**
-   * Start a value at the current position.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * (It should already be started; this is just a self-documentation method.)
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
   /**
-   * Resume a value.
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
 
   /**
-   * Get the object, starting or resuming it as necessary
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
    */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
 
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
+   */
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
 
-  value_iterator iter{};
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
+
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
+   */
+  inline void rewind() noexcept;
+  /**
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
+   */
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
+  simdjson_inline token_position last_position() const noexcept;
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
+  simdjson_inline token_position end_position() const noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
 
   friend class document;
-  friend class array_iterator;
-  friend class field;
+  friend class document_stream;
   friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
+  friend class array;
+  friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
   friend class field;
-};
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
 
 } // namespace ondemand
 } // namespace lasx
@@ -115868,204 +120331,189 @@ class value {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::value> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value> {
+struct simdjson_result<lasx::ondemand::json_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::json_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+
   simdjson_inline simdjson_result() noexcept = default;
+};
 
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() noexcept;
+} // namespace simdjson
 
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for lasx */
+/* including simdjson/generic/ondemand/json_type.h for lasx: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
 
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+/**
+ * The type of a JSON value.
+ */
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
+
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
 
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) noexcept;
-
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
   /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
    */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) noexcept = delete;
-
+  simdjson_inline bool is_uint64() const noexcept;
   /**
-   * Get the type of this JSON value.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * return the value as a uint64_t, only valid if is_uint64() is true.
    */
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
-
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
+   */
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for lasx */
-/* including simdjson/generic/ondemand/logger.h for lasx: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
+   */
+  simdjson_inline bool is_double() const noexcept;
+  /**
+   * return the value as a double, only valid if is_double() is true.
+   */
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
+   */
+  simdjson_inline double as_double() const noexcept;
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
 
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
+protected:
+  /**
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
+   */
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
+  /**
+   * End of friend declarations.
+   */
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
+  /**
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
+   */
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
 };
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
-#endif
-
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
 
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+#if SIMDJSON_EXCEPTIONS
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
+#endif
 
-} // namespace logger
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for lasx */
-/* including simdjson/generic/ondemand/token_iterator.h for lasx: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::json_type> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_type> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for lasx */
+/* including simdjson/generic/ondemand/raw_json_string.h for lasx: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -116073,132 +120521,177 @@ namespace lasx {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
+ *
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
+ *
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
  *
- * @private This is not intended for external use.
  */
-class token_iterator {
+class raw_json_string {
 public:
   /**
-   * Create a new invalid token_iterator.
+   * Create a new invalid raw_json_string.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * Advance to the next token (returning the current one).
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
-  /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
-   */
-  simdjson_inline uint32_t current_offset() const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * The given location must be just *after* the beginning quote (") in the JSON file.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * It *must* be terminated by a ", and be a valid JSON string.
+   */
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  /**
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  simdjson_inline const char * raw() const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
    *
-   * The length will include any whitespace at the end of the token.
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
 
   /**
-   * Get the JSON text for a given token.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
    *
-   * @param position The position of the token.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * The length will include any whitespace at the end of the token.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * @param position The position of the token.
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a root token.
-   *
-   * The length will include any whitespace at the end of the token.
-   *
-   * @param position The position of the token (start of the document).
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+
   /**
-   * Return the current index.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline token_position position() const noexcept;
+  simdjson_inline bool is_equal(const char* target) const noexcept;
+
   /**
-   * Reset to a previously saved index.
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
 
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
+private:
 
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
 
-protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+  /**
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
+   */
+  simdjson_inline void consume() noexcept { buf = nullptr; }
 
   /**
-   * Get the index of the JSON text for a given token (relative).
+   * Checks whether the inner pointer is non-null and thus usable.
+   */
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ## IMPORTANT: string_view lifetime
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+
   /**
-   * Get the index of the JSON text for a given token.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ## IMPORTANT: string_view lifetime
    *
-   * @param position The position of the token.
+   * The string_view is only valid until the next parse() call on the parser.
    *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
-
-  const uint8_t *buf{};
-  token_position _position{};
-
-  friend class json_iterator;
-  friend class value_iterator;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
   friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
 };
 
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+
+
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
@@ -116206,339 +120699,398 @@ class token_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::token_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::token_iterator> {
+struct simdjson_result<lasx::ondemand::raw_json_string> : public lasx::implementation_simdjson_result_base<lasx::ondemand::raw_json_string> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
   simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for lasx */
-/* including simdjson/generic/ondemand/json_iterator.h for lasx: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for lasx */
+/* including simdjson/generic/ondemand/parser.h for lasx: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
+ */
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
  *
- * @private This is not intended for external use.
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
  */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
-  /**
-   * Next free location in the string buffer.
-   *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
-   */
-  uint8_t *_string_buf_loc{};
-  /**
-   * JSON error, if there is one.
-   *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
-   *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
-   */
-  error_code error{SUCCESS};
-  /**
-   * Depth of the current token in the JSON.
-   *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
-   */
-  bool _streaming{false};
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
 
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
 public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
-
-  /**
-   * Tell whether the iterator is still at the start
-   */
-  simdjson_inline bool at_root() const noexcept;
-
-  /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
-   */
-  simdjson_inline bool streaming() const noexcept;
-
-  /**
-   * Get the root value iterator
-   */
-  simdjson_inline token_position root_position() const noexcept;
-  /**
-   * Assert that we are at the document depth (== 1)
-   */
-  simdjson_inline void assert_at_document_depth() const noexcept;
-  /**
-   * Assert that we are at the root of the document
-   */
-  simdjson_inline void assert_at_root() const noexcept;
-
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
-
   /**
-   * Tell whether the iterator is live (has not been moved).
+   * Create a JSON parser.
+   *
+   * The new parser will have zero capacity.
    */
-  simdjson_inline bool is_alive() const noexcept;
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
 
-  /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
-   */
-  simdjson_inline void abandon() noexcept;
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
 
-  /**
-   * Advance the current token without modifying depth.
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Start iterating an on-demand JSON document.
    *
-   * @return whether there is a single token
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
+   *
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
+   *
+   * ### IMPORTANT: Validate what you use
+   *
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
+   *
+   * ### IMPORTANT: Buffer Lifetime
+   *
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
+   *
+   * ### IMPORTANT: Document Lifetime
+   *
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * ### std::string references
+   *
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   *
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
+   *
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
+   *
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline bool is_single_token() const noexcept;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
 
   /**
-   * Assert that there are at least the given number of tokens left.
+   * @private
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
-  /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * Start iterating an on-demand JSON document.
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   *   ondemand::parser parser;
+   *   json_iterator doc = parser.iterate(json);
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * ### IMPORTANT: Document Lifetime
    *
-   * The length will include any whitespace at the end of the token.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * @param json The JSON to parse.
+   *
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+
+
   /**
-   * Get a pointer to the current location in the input buffer.
+   * Parse a buffer containing many JSON documents.
+   *
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
+   *
+   * No copy of the input buffer is made.
+   *
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   *
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### Format
    *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
-   */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
-  /**
-   * Get the JSON text for a given token.
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
    *
-   * @param position The position of the token to retrieve.
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
    *
-   * The length will include any whitespace at the end of the token.
+   * ### REQUIRED: Buffer Padding
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current root token.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * The length will include any whitespace at the end of the token.
+   * ### Threads
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
-  /**
-   * Get the JSON text for the last token in the document.
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### Parser Capacity
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
+   *
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
    */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
 
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Ascend one level.
-   *
-   * Validates that the depth - 1 == parent_depth.
-   *
-   * @param parent_depth the expected parent depth.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
 
   /**
-   * Descend one level.
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
    *
-   * Validates that the new depth == child_depth.
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    *
-   * @param child_depth the expected child depth.
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
 
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * Get current depth.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  simdjson_inline depth_t depth() const noexcept;
-
+  bool threaded{true};
+  #else
   /**
-   * Get current (writeable) location in the string buffer.
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-
+  bool threaded{false};
+  #endif
   /**
-   * Report an unrecoverable error, preventing further iteration.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
-  /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
 
   /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   *
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
 
-  simdjson_inline token_position position() const noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
-
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
+#endif
 
-  simdjson_inline error_code consume_character(char c) noexcept;
+private:
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+  std::unique_ptr<token_position[]> start_positions{};
 #endif
 
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
-   */
-  inline void rewind() noexcept;
-  /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
-   */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
-
-  friend class document;
+  friend class json_iterator;
   friend class document_stream;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
+};
 
 } // namespace ondemand
 } // namespace lasx
@@ -116547,27 +121099,28 @@ class json_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::json_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_iterator> {
+struct simdjson_result<lasx::ondemand::parser> : public lasx::implementation_simdjson_result_base<lasx::ondemand::parser> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::json_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::parser &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-
   simdjson_inline simdjson_result() noexcept = default;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for lasx */
-/* including simdjson/generic/ondemand/json_type.h for lasx: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for lasx */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for lasx: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -116575,133 +121128,180 @@ namespace lasx {
 namespace ondemand {
 
 /**
- * The type of a JSON value.
- */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
-
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
+ * A forward-only JSON array.
  */
-struct number {
+class array {
+public:
+  /**
+   * Create a new invalid array.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline array() noexcept = default;
 
   /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+   * Begin array iteration.
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
+   * Part of the std::iterable interface.
    */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline bool is_uint64() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
   /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   *
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    */
-  simdjson_inline bool is_int64() const noexcept;
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
   /**
-   * return the value as a int64_t, only valid if is_int64() is true.
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
+   *
+   * @returns true if the array contains some elements (not empty)
    */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline bool is_double() const noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
   /**
-   * return the value as a double, only valid if is_double() is true.
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
-
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+protected:
   /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Go to the end of the array, no matter where you are right now.
    */
-  simdjson_inline double as_double() const noexcept;
-
+  simdjson_inline error_code consume() noexcept;
 
-protected:
   /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
+   * Begin array iteration.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
    */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
   /**
-   * End of friend declarations.
+   * Begin array iteration from the root.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
    */
-
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
   /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
+   * Begin array iteration.
+   *
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
+   *
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
    */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
 
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+  /**
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
+   *
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
+   */
+  simdjson_inline array(const value_iterator &iter) noexcept;
 
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
+  /**
+   * Iterator marking current position.
+   *
+   * iter.is_alive() == false indicates iteration is complete.
+   */
+  value_iterator iter{};
+
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
+};
 
 } // namespace ondemand
 } // namespace lasx
@@ -116710,204 +121310,100 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &t
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::json_type> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_type> {
+struct simdjson_result<lasx::ondemand::array> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::array &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for lasx */
-/* including simdjson/generic/ondemand/raw_json_string.h for lasx: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for lasx */
+/* including simdjson/generic/ondemand/array_iterator.h for lasx: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
- *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
+ * A forward-only JSON array.
  *
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
  */
-class raw_json_string {
+class array_iterator {
 public:
-  /**
-   * Create a new invalid raw_json_string.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline raw_json_string() noexcept = default;
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
 
-  /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
-   *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
-   *
-   * It *must* be terminated by a ", and be a valid JSON string.
-   */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
-  /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
-   *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
-   */
-  simdjson_inline const char * raw() const noexcept;
+  //
+  // Iterator interface
+  //
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
-   *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * Get the current element.
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * Part of the std::iterator interface.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
-
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
-   *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
+   * Check if we are at the end of the JSON.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Part of the std::iterator interface.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * @return true if there are no more elements in the JSON array.
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
-
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Check if there are more elements in the JSON array.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Part of the std::iterator interface.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
-   */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
-
-  /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
-
-  /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * @return true if there are more elements in the JSON array.
    */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
-
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
+  simdjson_inline array_iterator &operator++() noexcept;
 
 private:
+  value_iterator iter{};
 
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
 
-  /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
-   */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
-
-  /**
-   * Checks whether the inner pointer is non-null and thus usable.
-   */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
-
-  /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
-
-  /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
 };
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
-
-/**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
- */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
-
-
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
@@ -116915,524 +121411,702 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::raw_json_string> : public lasx::implementation_simdjson_result_base<lasx::ondemand::raw_json_string> {
+struct simdjson_result<lasx::ondemand::array_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::array_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept;
+  //
+  // Iterator interface
+  //
+
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &operator++() noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for lasx */
-/* including simdjson/generic/ondemand/parser.h for lasx: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for lasx */
+/* including simdjson/generic/ondemand/document.h for lasx: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
+ * A JSON document. It holds a json_iterator instance.
  *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
-
-/**
- * A JSON fragment iterator.
+ * Used by tokens to get text, and string buffer location.
  *
- * This holds the actual iterator as well as the buffer for writing strings.
+ * You must keep the document around during iteration.
  */
-class parser {
+class document {
 public:
   /**
-   * Create a JSON parser.
+   * Create a new invalid document.
    *
-   * The new parser will have zero capacity.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
 
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+  /**
+   * Cast this JSON value (inside string) to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: Calling get_string() twice on the same document is an error.
+   *
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   */
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline simdjson_result<value> get_value() noexcept;
 
   /**
-   * Start iterating an on-demand JSON document.
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  /**
+   * Get this value as the given type.
    *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * ### IMPORTANT: Validate what you use
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
    *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
    *
-   * ### IMPORTANT: Buffer Lifetime
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
    *
-   * ### IMPORTANT: Document Lifetime
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
    *
-   * ### REQUIRED: Buffer Padding
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * ### std::string references
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
+
+  /**
+   * Cast this JSON value to an array.
    *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() & noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() & noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
    *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
    *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
-
+  simdjson_inline operator double() noexcept(false);
   /**
-   * @private
+   * Cast this JSON value to a string.
    *
-   * Start iterating an on-demand JSON document.
+   * The string is guaranteed to be valid UTF-8.
    *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * ### IMPORTANT: Buffer Lifetime
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
    *
-   * ### IMPORTANT: Document Lifetime
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
    *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline operator value() noexcept(false);
+#endif
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * ### REQUIRED: Buffer Padding
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  /**
+   * Begin array iteration.
    *
-   * @param json The JSON to parse.
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
    *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * Part of the std::iterable interface.
    */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
-
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
 
   /**
-   * Parse a buffer containing many JSON documents.
-   *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
-   *
-   * No copy of the input buffer is made.
-   *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * ### Format
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
    *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
    *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * is an error.
    *
-   * ### REQUIRED: Buffer Padding
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+
+  /**
+   * Look up a field by name on an object, without regard to key order.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * ### Threads
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
    *
-   * ### Parser Capacity
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
    *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
   /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
-   *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
 
-  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  bool threaded{true};
-  #else
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid as long as the bytes in dst.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * @returns true if the number if negative.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
-
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * ## IMPORTANT: string_view lifetime
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
-   */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
-
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
-
-  friend class json_iterator;
-  friend class document_stream;
-};
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::parser> : public lasx::implementation_simdjson_result_base<lasx::ondemand::parser> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::parser &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for lasx */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for lasx: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-/**
- * A forward-only JSON array.
- */
-class array {
-public:
-  /**
-   * Create a new invalid array.
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @returns the type of the number
    */
-  simdjson_inline array() noexcept = default;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * Begin array iteration.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * Part of the std::iterable interface.
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
   /**
-   * Sentinel representing the end of the array.
+   * Get the raw JSON for this token.
    *
-   * Part of the std::iterable interface.
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
    */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  inline void rewind() noexcept;
   /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Returns debugging information.
    */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  inline std::string to_debug_string() noexcept;
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
    *
-   * @returns true if the array contains some elements (not empty)
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+
   /**
    * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
    *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
    *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
+   *   doc.at_pointer("/foo/a/1") == 20
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
+   * It is allowed for a key to be the empty string:
    *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
@@ -117441,397 +122115,92 @@ class array {
    *
    * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
    *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 protected:
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * Consumes the document.
    */
   simdjson_inline error_code consume() noexcept;
 
-  /**
-   * Begin array iteration.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
-  /**
-   * Begin array iteration from the root.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
-   */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
-  /**
-   * Begin array iteration.
-   *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
-   *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
-   */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
-
-  /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
-   *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
-   */
-  simdjson_inline array(const value_iterator &iter) noexcept;
-
-  /**
-   * Iterator marking current position.
-   *
-   * iter.is_alive() == false indicates iteration is complete.
-   */
-  value_iterator iter{};
-
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
-  friend class array_iterator;
-};
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::array> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::array &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for lasx */
-/* including simdjson/generic/ondemand/array_iterator.h for lasx: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
 
-/**
- * A forward-only JSON array.
- *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
- */
-class array_iterator {
-public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
 
   //
-  // Iterator interface
+  // Fields
   //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
 
-  /**
-   * Get the current element.
-   *
-   * Part of the std::iterator interface.
-   */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  /**
-   * Check if we are at the end of the JSON.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are no more elements in the JSON array.
-   */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
-  /**
-   * Check if there are more elements in the JSON array.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are more elements in the JSON array.
-   */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
-  /**
-   * Move to the next element.
-   *
-   * Part of the std::iterator interface.
-   */
-  simdjson_inline array_iterator &operator++() noexcept;
-
-private:
-  value_iterator iter{};
-
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
-
-  friend class array;
+  friend class array_iterator;
   friend class value;
-  friend struct simdjson_result<array_iterator>;
-};
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::array_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::array_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &operator++() noexcept;
+  friend class ondemand::parser;
+  friend class object;
+  friend class array;
+  friend class field;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
 };
 
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for lasx */
-/* including simdjson/generic/ondemand/document.h for lasx: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
- *
- * Used by tokens to get text, and string buffer location.
- *
- * You must keep the document around during iteration.
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
-class document {
+class document_reference {
 public:
-  /**
-   * Create a new invalid document.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
   simdjson_inline simdjson_result<array> get_array() & noexcept;
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
   simdjson_inline simdjson_result<object> get_object() & noexcept;
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
   simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
   simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: Calling get_string() twice on the same document is an error.
-   *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
   simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
   template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
   simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
-  /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
   template <typename T>
   simdjson_inline simdjson_result<T> get() &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -117845,16 +122214,6 @@ class document {
     SIMDJSON_TRY(get<T>(out));
     return out;
   }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
   template<typename T>
   simdjson_inline simdjson_result<T> get() &&
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -117863,7 +122222,7 @@ class document {
     noexcept
 #endif
   {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
       return static_cast<document&>(*this).get<T>();
   }
 
@@ -117881,13 +122240,13 @@ class document {
   template<typename T>
   simdjson_inline error_code get(T &out) &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
 #else
     noexcept
 #endif
   {
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
+    if constexpr (custom_deserializable<T, document_reference>) {
         return deserialize(*this, out);
     } else {
 #endif // SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -117905,146 +122264,697 @@ class document {
 #endif
   }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+private:
+  document *doc{nullptr};
+};
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::document> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lasx::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_reference> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
 
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lasx::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+/* end file simdjson/generic/ondemand/document.h for lasx */
+/* including simdjson/generic/ondemand/document_stream.h for lasx: #include "simdjson/generic/ondemand/document_stream.h" */
+/* begin file simdjson/generic/ondemand/document_stream.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+/** @private Custom worker class **/
+struct stage1_worker {
+  stage1_worker() noexcept = default;
+  stage1_worker(const stage1_worker&) = delete;
+  stage1_worker(stage1_worker&&) = delete;
+  stage1_worker operator=(const stage1_worker&) = delete;
+  ~stage1_worker();
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
+   * We only start the thread when it is needed, not at object construction, this may throw.
+   * You should only call this once.
+   **/
+  void start_thread();
+  /**
+   * Start a stage 1 job. You should first call 'run', then 'finish'.
+   * You must call start_thread once before.
+   */
+  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
+  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
+  void finish();
+
+private:
+
+  /**
+   * Normally, we would never stop the thread. But we do in the destructor.
+   * This function is only safe assuming that you are not waiting for results. You
+   * should have called run, then finish, and be done.
+   **/
+  void stop_thread();
+
+  std::thread thread{};
+  /** These three variables define the work done by the thread. **/
+  ondemand::parser * stage1_thread_parser{};
+  size_t _next_batch_start{};
+  document_stream * owner{};
+  /**
+   * We have two state variables. This could be streamlined to one variable in the future but
+   * we use two for clarity.
+   */
+  bool has_work{false};
+  bool can_work{true};
+
+  /**
+   * We lock using a mutex.
+   */
+  std::mutex locking_mutex{};
+  std::condition_variable cond_var{};
+
+  friend class document_stream;
+};
+#endif  // SIMDJSON_THREADS_ENABLED
+
+/**
+ * A forward-only stream of documents.
+ *
+ * Produced by parser::iterate_many.
+ *
+ */
+class document_stream {
+public:
+  /**
+   * Construct an uninitialized document_stream.
+   *
+   *  ```c++
+   *  document_stream docs;
+   *  auto error = parser.iterate_many(json).get(docs);
+   *  ```
+   */
+  simdjson_inline document_stream() noexcept;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream(document_stream &&other) noexcept = default;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+
+  simdjson_inline ~document_stream() noexcept;
+
+  /**
+   * Returns the input size in bytes.
+   */
+  inline size_t size_in_bytes() const noexcept;
+
+  /**
+   * After iterating through the stream, this method
+   * returns the number of bytes that were not parsed at the end
+   * of the stream. If truncated_bytes() differs from zero,
+   * then the input was truncated maybe because incomplete JSON
+   * documents were found at the end of the stream. You
+   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   *
+   * You should only call truncated_bytes() after streaming through all
+   * documents, like so:
+   *
+   *   document_stream stream = parser.iterate_many(json,window);
+   *   for(auto & doc : stream) {
+   *      // do something with doc
+   *   }
+   *   size_t truncated = stream.truncated_bytes();
+   *
+   */
+  inline size_t truncated_bytes() const noexcept;
+
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
+
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
+
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
+
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
+
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
+
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
+
+  /**
+   * Start iterating the documents in the stream.
+   */
+  simdjson_inline iterator begin() noexcept;
+  /**
+   * The end of the stream, for iterator comparison purposes.
+   */
+  simdjson_inline iterator end() noexcept;
+
+private:
+
+  document_stream &operator=(const document_stream &) = delete; // Disallow copying
+  document_stream(const document_stream &other) = delete; // Disallow copying
+
+  /**
+   * Construct a document_stream. Does not allocate or parse anything until the iterator is
+   * used.
+   *
+   * @param parser is a reference to the parser instance used to generate this document_stream
+   * @param buf is the raw byte buffer we need to process
+   * @param len is the length of the raw byte buffer in bytes
+   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   */
+  simdjson_inline document_stream(
+    ondemand::parser &parser,
+    const uint8_t *buf,
+    size_t len,
+    size_t batch_size,
+    bool allow_comma_separated
+  ) noexcept;
+
+  /**
+   * Parse the first document in the buffer. Used by begin(), to handle allocation and
+   * initialization.
+   */
+  inline void start() noexcept;
+
+  /**
+   * Parse the next document found in the buffer previously given to document_stream.
+   *
+   * The content should be a valid JSON document encoded as UTF-8. If there is a
+   * UTF-8 BOM, the parser skips it.
+   *
+   * You do NOT need to pre-allocate a parser.  This function takes care of
+   * pre-allocating a capacity defined by the batch_size defined when creating the
+   * document_stream object.
    *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   * The function returns simdjson::EMPTY if there is no more data to be parsed.
    *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
-  template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
-
-  /**
-   * Cast this JSON value to an array.
+   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
+   * and indicates that the buffer has successfully been parsed to the end.
+   * Every document it contained has been parsed without error.
    *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
+   * The function returns an error code from simdjson/simdjson.h in case of failure
+   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
+   * the simdjson::error_message function converts these error codes into a string).
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   * You can also check validity by calling parser.is_valid(). The same parser can
+   * and should be reused for the other documents in the buffer.
    */
-  simdjson_inline operator object() & noexcept(false);
+  inline void next() noexcept;
+
+  /** Move the json_iterator of the document to the location of the next document in the stream. */
+  inline void next_document() noexcept;
+
+  /** Get the next document index. */
+  inline size_t next_batch_start() const noexcept;
+
+  /** Pass the next batch through stage 1 with the given parser. */
+  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+
+  // Fields
+  ondemand::parser *parser;
+  const uint8_t *buf;
+  size_t len;
+  size_t batch_size;
+  bool allow_comma_separated;
   /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * We are going to use just one document instance. The document owns
+   * the json_iterator. It implies that we only ever pass a reference
+   * to the document to the users.
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  document doc{};
+  /** The error (or lack thereof) from the current document. */
+  error_code error;
+  size_t batch_start{0};
+  size_t doc_index{};
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
+  bool use_thread;
+
+  inline void load_from_stage1_thread() noexcept;
+
+  /** Start a thread to run stage 1 on the next batch. */
+  inline void start_stage1_thread() noexcept;
+
+  /** Wait for the stage 1 thread to finish and capture the results. */
+  inline void finish_stage1_thread() noexcept;
+
+  /** The error returned from the stage 1 thread. */
+  error_code stage1_thread_error{UNINITIALIZED};
+  /** The thread used to run stage 1 against the next batch in the background. */
+  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
   /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   * The parser used to run stage 1 in the background. Will be swapped
+   * with the regular parser when finished.
    */
-  simdjson_inline operator int64_t() noexcept(false);
+  ondemand::parser stage1_thread_parser{};
+
+  friend struct stage1_worker;
+  #endif // SIMDJSON_THREADS_ENABLED
+
+  friend class parser;
+  friend class document;
+  friend class json_iterator;
+  friend struct simdjson_result<ondemand::document_stream>;
+  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
+};  // document_stream
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+template<>
+struct simdjson_result<lasx::ondemand::document_stream> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_stream> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::document_stream &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+/* end file simdjson/generic/ondemand/document_stream.h for lasx */
+/* including simdjson/generic/ondemand/field.h for lasx: #include "simdjson/generic/ondemand/field.h" */
+/* begin file simdjson/generic/ondemand/field.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+/**
+ * A JSON field (key/value pair) in an object.
+ *
+ * Returned from object iteration.
+ *
+ * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
+ */
+class field : public std::pair<raw_json_string, value> {
+public:
   /**
-   * Cast this JSON value to a double.
+   * Create a new invalid field.
    *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline field() noexcept;
+
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it. The content is stored in the receiver.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline operator raw_json_string() noexcept(false);
+  template <typename string_type>
+  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * Get the key as a raw_json_string. Can be used for direct comparison with
+   * an unescaped C string: e.g., key() == "test". This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key() for a similar function which returns
+   * a more convenient std::string_view result.
    */
-  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline raw_json_string key() const noexcept;
   /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
    */
-  simdjson_inline operator value() noexcept(false);
-#endif
+  simdjson_inline std::string_view key_raw_json_token() const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
+   * Get the key as a string_view. This does not include the quotes and
+   * the string is unprocessed key so it may contain escape characters
+   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
+   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
    */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline std::string_view escaped_key() const noexcept;
   /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Get the field value.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline ondemand::value &value() & noexcept;
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * @overload ondemand::value &ondemand::value() & noexcept
    */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline ondemand::value value() && noexcept;
+
+protected:
+  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
+  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
+  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
+  friend struct simdjson_result<field>;
+  friend class object_iterator;
+};
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::field> : public lasx::implementation_simdjson_result_base<lasx::ondemand::field> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::field &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  template<typename string_type>
+  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> value() noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+/* end file simdjson/generic/ondemand/field.h for lasx */
+/* including simdjson/generic/ondemand/object.h for lasx: #include "simdjson/generic/ondemand/object.h" */
+/* begin file simdjson/generic/ondemand/object.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+/**
+ * A forward-only JSON object field iterator.
+ */
+class object {
+public:
   /**
-   * Sentinel representing the end of the array.
+   * Create a new invalid object.
    *
-   * Part of the std::iterable interface.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline object() noexcept = default;
 
+  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<object_iterator> end() noexcept;
   /**
    * Look up a field by name on an object (order-sensitive).
    *
@@ -118058,28 +122968,32 @@ class document {
    * double y = obj.find_field("y");
    * double x = obj.find_field("x");
    * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
    * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
    * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   *
    * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
    * given by content["bids"].get_array() should not be accessed after you have called
    * content["asks"].get_array(). You can detect such mistakes by first compiling and running
    * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
    * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * You are expected to access keys only once. You should access the value corresponding to a
+   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
    * is an error.
    *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
   simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
 
   /**
    * Look up a field by name on an object, without regard to key order.
@@ -118097,195 +123011,37 @@ class document {
    * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
    * field was not there when they are not in order).
    *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
    * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
    * given by content["bids"].get_array() should not be accessed after you have called
    * content["asks"].get_array(). You can detect such mistakes by first compiling and running
    * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
    * OUT_OF_ORDER_ITERATION error is generated.
    *
    * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
    *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
+   * Get the value associated with the given JSON pointer. We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
    *   ondemand::parser parser;
    *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
@@ -118299,233 +123055,190 @@ class document {
    *   auto doc = parser.iterate(json);
    *   doc.at_pointer("//a/1") == 20
    *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
+   * instance: there is no rewind and no invalidation.
    *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
    * JSONPath queries that trivially convertible to JSON Pointer queries: key
    * names and array indices.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
-   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the object. You should still consume values only once even if you
+   * can iterate through the object more than once. If you unescape a string or a key
+   * within the object more than once, you have unsafe code. Note that rewinding an object
+   * means that you may need to reparse it anew: it is not a free operation.
+   *
+   * @returns true if the object contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * This method scans the beginning of the object and checks whether the
+   * object is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Consumes the object and returns a string_view instance corresponding to the
+   * object as represented in JSON. It points inside the original byte array containing
    * the JSON document.
    */
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 protected:
   /**
-   * Consumes the document.
+   * Go to the end of the object, no matter where you are right now.
    */
   simdjson_inline error_code consume() noexcept;
+  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
+  static simdjson_inline object resume(const value_iterator &iter) noexcept;
+  simdjson_inline object(const value_iterator &iter) noexcept;
 
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
+  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
 
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+  value_iterator iter{};
 
-  friend class array_iterator;
   friend class value;
-  friend class ondemand::parser;
-  friend class object;
-  friend class array;
-  friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
+  friend class document;
+  friend struct simdjson_result<object>;
 };
 
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::object> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object> {
 public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
+  simdjson_inline simdjson_result(lasx::ondemand::object &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> end() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+
+  inline simdjson_result<bool> reset() noexcept;
+  inline simdjson_result<bool> is_empty() noexcept;
+  inline simdjson_result<size_t> count_fields() & noexcept;
+  inline simdjson_result<std::string_view> raw_json() noexcept;
+
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+/* end file simdjson/generic/ondemand/object.h for lasx */
+/* including simdjson/generic/ondemand/object_iterator.h for lasx: #include "simdjson/generic/ondemand/object_iterator.h" */
+/* begin file simdjson/generic/ondemand/object_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
+class object_iterator {
+public:
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   * Create a new invalid object_iterator.
    *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline object_iterator() noexcept = default;
 
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  //
+  // Iterator interface
+  //
 
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  // Reads key and value, yielding them to the user.
+  // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline simdjson_result<field> operator*() noexcept;
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const object_iterator &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline object_iterator &operator++() noexcept;
 
 private:
-  document *doc{nullptr};
+  /**
+   * The underlying JSON iterator.
+   *
+   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
+   * is first used, and never changes afterwards.
+   */
+  value_iterator iter{};
+
+  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
+  friend struct simdjson_result<object_iterator>;
+  friend class object;
 };
+
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
@@ -118533,588 +123246,491 @@ class document_reference {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::document> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document> {
+struct simdjson_result<lasx::ondemand::object_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::object_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lasx::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool at_end() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  //
+  // Iterator interface
+  //
 
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  // Reads key and value, yielding them to the user.
+  simdjson_inline simdjson_result<lasx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &operator++() noexcept;
 };
 
-
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+/* end file simdjson/generic/ondemand/object_iterator.h for lasx */
+/* including simdjson/generic/ondemand/serialization.h for lasx: #include "simdjson/generic/ondemand/serialization.h" */
+/* begin file simdjson/generic/ondemand/serialization.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+/**
+ * Create a string-view instance out of a document instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept;
+/**
+ * Create a string-view instance out of a value instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. The value must
+ * not have been accessed previously. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept;
+/**
+ * Create a string-view instance out of an object instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept;
+/**
+ * Create a string-view instance out of an array instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x);
+} // namespace simdjson
 
-template<>
-struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_reference> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::document_reference value, error_code error) noexcept;
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+/**
+ * We want to support argument-dependent lookup (ADL).
+ * Hence we should define operator<< in the namespace
+ * where the argument (here value, object, etc.) resides.
+ * Credit: @madhur4127
+ * See https://github.com/simdjson/simdjson/issues/1768
+ */
+namespace simdjson { namespace lasx { namespace ondemand {
 
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+/**
+ * Print JSON to an output stream.  It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The element.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x);
 #if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lasx::ondemand::value() noexcept(false);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x);
+#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The object.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::object> x);
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
-
+}}} // namespace simdjson::lasx::ondemand
 
-} // namespace simdjson
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+/* end file simdjson/generic/ondemand/serialization.h for lasx */
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-/* end file simdjson/generic/ondemand/document.h for lasx */
-/* including simdjson/generic/ondemand/document_stream.h for lasx: #include "simdjson/generic/ondemand/document_stream.h" */
-/* begin file simdjson/generic/ondemand/document_stream.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for lasx: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for lasx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
+#include <concepts>
+#include <limits>
 
 namespace simdjson {
-namespace lasx {
-namespace ondemand {
+template <typename T>
+constexpr bool require_custom_serialization = false;
 
-#ifdef SIMDJSON_THREADS_ENABLED
-/** @private Custom worker class **/
-struct stage1_worker {
-  stage1_worker() noexcept = default;
-  stage1_worker(const stage1_worker&) = delete;
-  stage1_worker(stage1_worker&&) = delete;
-  stage1_worker operator=(const stage1_worker&) = delete;
-  ~stage1_worker();
-  /**
-   * We only start the thread when it is needed, not at object construction, this may throw.
-   * You should only call this once.
-   **/
-  void start_thread();
-  /**
-   * Start a stage 1 job. You should first call 'run', then 'finish'.
-   * You must call start_thread once before.
-   */
-  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
-  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
-  void finish();
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
 
-private:
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  /**
-   * Normally, we would never stop the thread. But we do in the destructor.
-   * This function is only safe assuming that you are not waiting for results. You
-   * should have called run, then finish, and be done.
-   **/
-  void stop_thread();
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  std::thread thread{};
-  /** These three variables define the work done by the thread. **/
-  ondemand::parser * stage1_thread_parser{};
-  size_t _next_batch_start{};
-  document_stream * owner{};
-  /**
-   * We have two state variables. This could be streamlined to one variable in the future but
-   * we use two for clarity.
-   */
-  bool has_work{false};
-  bool can_work{true};
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  /**
-   * We lock using a mutex.
-   */
-  std::mutex locking_mutex{};
-  std::condition_variable cond_var{};
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  friend class document_stream;
-};
-#endif  // SIMDJSON_THREADS_ENABLED
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
 /**
- * A forward-only stream of documents.
- *
- * Produced by parser::iterate_many.
- *
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
  */
-class document_stream {
-public:
-  /**
-   * Construct an uninitialized document_stream.
-   *
-   *  ```c++
-   *  document_stream docs;
-   *  auto error = parser.iterate_many(json).get(docs);
-   *  ```
-   */
-  simdjson_inline document_stream() noexcept;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream(document_stream &&other) noexcept = default;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
-
-  simdjson_inline ~document_stream() noexcept;
-
-  /**
-   * Returns the input size in bytes.
-   */
-  inline size_t size_in_bytes() const noexcept;
-
-  /**
-   * After iterating through the stream, this method
-   * returns the number of bytes that were not parsed at the end
-   * of the stream. If truncated_bytes() differs from zero,
-   * then the input was truncated maybe because incomplete JSON
-   * documents were found at the end of the stream. You
-   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
-   *
-   * You should only call truncated_bytes() after streaming through all
-   * documents, like so:
-   *
-   *   document_stream stream = parser.iterate_many(json,window);
-   *   for(auto & doc : stream) {
-   *      // do something with doc
-   *   }
-   *   size_t truncated = stream.truncated_bytes();
-   *
-   */
-  inline size_t truncated_bytes() const noexcept;
-
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
-
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
-
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
 
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
+  lasx::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
 
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
 
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
 
-  /**
-   * Start iterating the documents in the stream.
-   */
-  simdjson_inline iterator begin() noexcept;
-  /**
-   * The end of the stream, for iterator comparison purposes.
-   */
-  simdjson_inline iterator end() noexcept;
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
 
-private:
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
 
-  document_stream &operator=(const document_stream &) = delete; // Disallow copying
-  document_stream(const document_stream &other) = delete; // Disallow copying
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
 
-  /**
-   * Construct a document_stream. Does not allocate or parse anything until the iterator is
-   * used.
-   *
-   * @param parser is a reference to the parser instance used to generate this document_stream
-   * @param buf is the raw byte buffer we need to process
-   * @param len is the length of the raw byte buffer in bytes
-   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
-   */
-  simdjson_inline document_stream(
-    ondemand::parser &parser,
-    const uint8_t *buf,
-    size_t len,
-    size_t batch_size,
-    bool allow_comma_separated
-  ) noexcept;
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
 
-  /**
-   * Parse the first document in the buffer. Used by begin(), to handle allocation and
-   * initialization.
-   */
-  inline void start() noexcept;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
 
-  /**
-   * Parse the next document found in the buffer previously given to document_stream.
-   *
-   * The content should be a valid JSON document encoded as UTF-8. If there is a
-   * UTF-8 BOM, the parser skips it.
-   *
-   * You do NOT need to pre-allocate a parser.  This function takes care of
-   * pre-allocating a capacity defined by the batch_size defined when creating the
-   * document_stream object.
-   *
-   * The function returns simdjson::EMPTY if there is no more data to be parsed.
-   *
-   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
-   * and indicates that the buffer has successfully been parsed to the end.
-   * Every document it contained has been parsed without error.
-   *
-   * The function returns an error code from simdjson/simdjson.h in case of failure
-   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
-   * the simdjson::error_message function converts these error codes into a string).
-   *
-   * You can also check validity by calling parser.is_valid(). The same parser can
-   * and should be reused for the other documents in the buffer.
-   */
-  inline void next() noexcept;
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
 
-  /** Move the json_iterator of the document to the location of the next document in the stream. */
-  inline void next_document() noexcept;
+} // namespace simdjson
 
-  /** Get the next document index. */
-  inline size_t next_batch_start() const noexcept;
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for lasx */
 
-  /** Pass the next batch through stage 1 with the given parser. */
-  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for lasx: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
 
-  // Fields
-  ondemand::parser *parser;
-  const uint8_t *buf;
-  size_t len;
-  size_t batch_size;
-  bool allow_comma_separated;
-  /**
-   * We are going to use just one document instance. The document owns
-   * the json_iterator. It implies that we only ever pass a reference
-   * to the document to the users.
-   */
-  document doc{};
-  /** The error (or lack thereof) from the current document. */
-  error_code error;
-  size_t batch_start{0};
-  size_t doc_index{};
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
-  bool use_thread;
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-  inline void load_from_stage1_thread() noexcept;
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the array is first found and the iterator is just past the `{`.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
+//   depth == iter->depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter->depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the array iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
+//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
+//
+// ## Terminal State
+//
+// The terminal state has iter->depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
+//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
+//   error == SUCCESS.
+//
 
-  /** Start a thread to run stage 1 on the next batch. */
-  inline void start_stage1_thread() noexcept;
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
 
-  /** Wait for the stage 1 thread to finish and capture the results. */
-  inline void finish_stage1_thread() noexcept;
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  bool has_value;
+  SIMDJSON_TRY(iter.started_array().get(has_value));
+  return array(iter);
+}
 
-  /** The error returned from the stage 1 thread. */
-  error_code stage1_thread_error{UNINITIALIZED};
-  /** The thread used to run stage 1 against the next batch in the background. */
-  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
-  /**
-   * The parser used to run stage 1 in the background. Will be swapped
-   * with the regular parser when finished.
-   */
-  ondemand::parser stage1_thread_parser{};
+simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return array_iterator(iter);
+}
+simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
+  return array_iterator(iter);
+}
+simdjson_inline error_code array::consume() noexcept {
+  auto error = iter.json_iter().skip_child(iter.depth()-1);
+  if(error) { iter.abandon(); }
+  return error;
+}
 
-  friend struct stage1_worker;
-  #endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-  friend class parser;
-  friend class document;
-  friend class json_iterator;
-  friend struct simdjson_result<ondemand::document_stream>;
-  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
-};  // document_stream
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the array after counting the number of elements.
+  iter.reset_array();
+  return count;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
 
-namespace simdjson {
-template<>
-struct simdjson_result<lasx::ondemand::document_stream> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_stream> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::document_stream &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
 
-} // namespace simdjson
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
-/* end file simdjson/generic/ondemand/document_stream.h for lasx */
-/* including simdjson/generic/ondemand/field.h for lasx: #include "simdjson/generic/ondemand/field.h" */
-/* begin file simdjson/generic/ondemand/field.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
 
-/**
- * A JSON field (key/value pair) in an object.
- *
- * Returned from object iteration.
- *
- * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
- */
-class field : public std::pair<raw_json_string, value> {
-public:
-  /**
-   * Create a new invalid field.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline field() noexcept;
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
 
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it. The content is stored in the receiver.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  template <typename string_type>
-  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a raw_json_string. Can be used for direct comparison with
-   * an unescaped C string: e.g., key() == "test". This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key() for a similar function which returns
-   * a more convenient std::string_view result.
-   */
-  simdjson_inline raw_json_string key() const noexcept;
-  /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
-   */
-  simdjson_inline std::string_view key_raw_json_token() const noexcept;
-  /**
-   * Get the key as a string_view. This does not include the quotes and
-   * the string is unprocessed key so it may contain escape characters
-   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
-   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
-   */
-  simdjson_inline std::string_view escaped_key() const noexcept;
-  /**
-   * Get the field value.
-   */
-  simdjson_inline ondemand::value &value() & noexcept;
-  /**
-   * @overload ondemand::value &ondemand::value() & noexcept
-   */
-  simdjson_inline ondemand::value value() && noexcept;
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
 
-protected:
-  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
-  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
-  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
-  friend struct simdjson_result<field>;
-  friend class object_iterator;
-};
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
 
 } // namespace ondemand
 } // namespace lasx
@@ -119122,251 +123738,96 @@ class field : public std::pair<raw_json_string, value> {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<lasx::ondemand::field> : public lasx::implementation_simdjson_result_base<lasx::ondemand::field> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::field &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  template<typename string_type>
-  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> key() noexcept;
-  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> value() noexcept;
-};
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+  lasx::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(
+      std::forward<lasx::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
+{
+}
 
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-/* end file simdjson/generic/ondemand/field.h for lasx */
-/* including simdjson/generic/ondemand/object.h for lasx: #include "simdjson/generic/ondemand/object.h" */
-/* begin file simdjson/generic/ondemand/object.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for lasx */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-/**
- * A forward-only JSON object field iterator.
- */
-class object {
-public:
-  /**
-   * Create a new invalid object.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object() noexcept = default;
-
-  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<object_iterator> end() noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a
-   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
-
-  /**
-   * Get the value associated with the given JSON pointer. We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
-   * instance: there is no rewind and no invalidation.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the object. You should still consume values only once even if you
-   * can iterate through the object more than once. If you unescape a string or a key
-   * within the object more than once, you have unsafe code. Note that rewinding an object
-   * means that you may need to reparse it anew: it is not a free operation.
-   *
-   * @returns true if the object contains some elements (not empty)
-   */
-  inline simdjson_result<bool> reset() & noexcept;
-  /**
-   * This method scans the beginning of the object and checks whether the
-   * object is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   */
-  inline simdjson_result<bool> is_empty() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Consumes the object and returns a string_view instance corresponding to the
-   * object as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-protected:
-  /**
-   * Go to the end of the object, no matter where you are right now.
-   */
-  simdjson_inline error_code consume() noexcept;
-  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
-  static simdjson_inline object resume(const value_iterator &iter) noexcept;
-  simdjson_inline object(const value_iterator &iter) noexcept;
-
-  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
-
-  value_iterator iter{};
-
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<object>;
-};
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
 
 } // namespace ondemand
 } // namespace lasx
@@ -119374,86 +123835,280 @@ class object {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<lasx::ondemand::object> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::object &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> end() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-
-  inline simdjson_result<bool> reset() noexcept;
-  inline simdjson_result<bool> is_empty() noexcept;
-  inline simdjson_result<size_t> count_fields() & noexcept;
-  inline simdjson_result<std::string_view> raw_json() noexcept;
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
+  lasx::ondemand::array_iterator &&value
+) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
+{
+}
 
-};
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
-/* end file simdjson/generic/ondemand/object.h for lasx */
-/* including simdjson/generic/ondemand/object_iterator.h for lasx: #include "simdjson/generic/ondemand/object_iterator.h" */
-/* begin file simdjson/generic/ondemand/object_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-class object_iterator {
-public:
-  /**
-   * Create a new invalid object_iterator.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object_iterator() noexcept = default;
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
 
-  //
-  // Iterator interface
-  //
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
 
-  // Reads key and value, yielding them to the user.
-  // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline simdjson_result<field> operator*() noexcept;
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const object_iterator &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline object_iterator &operator++() noexcept;
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
 
-private:
-  /**
-   * The underlying JSON iterator.
-   *
-   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
-   * is first used, and never changes afterwards.
-   */
-  value_iterator iter{};
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
-  friend struct simdjson_result<object_iterator>;
-  friend class object;
-};
+
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
+
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
+
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
+
+
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
+
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
+
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace lasx
@@ -119461,138 +124116,252 @@ class object_iterator {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<lasx::ondemand::object_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object_iterator> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::object_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+  lasx::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(
+      std::forward<lasx::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
+}
+
+template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
+}
+
+template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
 
-  //
-  // Iterator interface
-  //
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 
-  // Reads key and value, yielding them to the user.
-  simdjson_inline simdjson_result<lasx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &operator++() noexcept;
-};
+simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
 
-} // namespace simdjson
+simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-/* end file simdjson/generic/ondemand/object_iterator.h for lasx */
-/* including simdjson/generic/ondemand/serialization.h for lasx: #include "simdjson/generic/ondemand/serialization.h" */
-/* begin file simdjson/generic/ondemand/serialization.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
+  }
+  return first.at_pointer(json_pointer);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
 
-namespace simdjson {
-/**
- * Create a string-view instance out of a document instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept;
-/**
- * Create a string-view instance out of a value instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. The value must
- * not have been accessed previously. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept;
-/**
- * Create a string-view instance out of an object instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept;
-/**
- * Create a string-view instance out of an array instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept;
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x);
 } // namespace simdjson
 
-/**
- * We want to support argument-dependent lookup (ADL).
- * Hence we should define operator<< in the namespace
- * where the argument (here value, object, etc.) resides.
- * Credit: @madhur4127
- * See https://github.com/simdjson/simdjson/issues/1768
- */
-namespace simdjson { namespace lasx { namespace ondemand {
-
-/**
- * Print JSON to an output stream.  It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The element.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x);
-#endif
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The object.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::object> x);
-#endif
-}}} // namespace simdjson::lasx::ondemand
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-/* end file simdjson/generic/ondemand/serialization.h for lasx */
-
 // Deserialization for standard types
 /* including simdjson/generic/ondemand/std_deserialize.h for lasx: #include "simdjson/generic/ondemand/std_deserialize.h" */
 /* begin file simdjson/generic/ondemand/std_deserialize.h for lasx */
@@ -119774,326 +124543,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser
 /* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the array is first found and the iterator is just past the `{`.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
-//   depth == iter->depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter->depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the array iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
-//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
-//
-// ## Terminal State
-//
-// The terminal state has iter->depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
-//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
-//   error == SUCCESS.
-//
-
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
-  bool has_value;
-  SIMDJSON_TRY(iter.started_array().get(has_value));
-  return array(iter);
-}
-
-simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return array_iterator(iter);
-}
-simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
-  return array_iterator(iter);
-}
-simdjson_inline error_code array::consume() noexcept {
-  auto error = iter.json_iter().skip_child(iter.depth()-1);
-  if(error) { iter.abandon(); }
-  return error;
-}
-
-simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the array after counting the number of elements.
-  iter.reset_array();
-  return count;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
-}
-
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
-}
-
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
-
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
-
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
-
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
-
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
-  }
-  return INDEX_OUT_OF_BOUNDS;
-}
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
-  lasx::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(
-      std::forward<lasx::ondemand::array>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
-  error_code error
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
-{
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
-}
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for lasx */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
-}
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
-}
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
-}
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
-  lasx::ondemand::array_iterator &&value
-) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
@@ -121690,7 +126139,7 @@ simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::on
 template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.get<T>();
 }
 simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -122332,6 +126781,443 @@ inline void document_stream::start() noexcept {
   #endif // SIMDJSON_THREADS_ENABLED
 }
 
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
+}
+
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
+}
+
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+}
+
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
+}
+
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
+}
+
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
+
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+}
+
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
+}
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
+}
+
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+}
+
+#endif // SIMDJSON_THREADS_ENABLED
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
+{
+}
+simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
+  lasx::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
+      std::forward<lasx::ondemand::document_stream>(value)
+    )
+{
+}
+
+}
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
+/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
+}
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
+}
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
+}
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
+}
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
+}
+
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
+}
+
+
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+}
+
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+}
+
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
+
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
+
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
+}
+
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
+}
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
+}
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
+}
+
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
+
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
+}
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
+}
+
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+}
+
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
+}
+
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
+}
+
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
+}
+
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
+}
+
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
+}
+
 inline void document_stream::next() noexcept {
   // We always enter at once once in an error condition.
   if (error) { return; }
@@ -123642,669 +128528,182 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_
       _depth--;
       if (depth() <= parent_depth) { return SUCCESS; }
       break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
-}
-
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
-}
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
-}
-
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
-}
-
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
-}
-
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-}
-
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
-}
-
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
-}
-
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
-
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
-}
-
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
-}
-
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
-}
-
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
-
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
-
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
-
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
-
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
-
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
-
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
-}
-
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
-}
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
-}
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
-}
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
-}
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
-}
-
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
-}
-
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
-}
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
-}
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
-}
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
-}
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
-}
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
-}
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
-}
-
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
-}
-
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
-}
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
-
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
-}
-#endif
-
-
-
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
-}
-
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
-}
-
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
-}
-
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
-}
-
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
-}
-
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
-}
-
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
-}
-
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
-}
-
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
-}
-
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
-}
-
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
-}
-
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
-}
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
-}
-
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
-}
-
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
-}
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
-/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  }
 
-#include <memory>
-#include <cstring>
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-namespace logger {
+  return report_error(TAPE_ERROR, "not enough close braces");
+}
 
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
+SIMDJSON_POP_DISABLE_WARNINGS
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
+}
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
-/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
+}
 
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
+}
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
@@ -124322,7 +128721,7 @@ simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_v
     }
     pos++;
   }
-  return value(iter.child());
+  return true;
 }
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
@@ -124342,10 +128741,18 @@ simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* t
     }
     pos++;
   }
-  return value(iter.child());
+  return true;
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
+}
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
@@ -124354,149 +128761,66 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) c
   if(target.size() <= SIMDJSON_PADDING) {
     return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
   }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
-}
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
-}
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
-}
-
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
 #endif
-  return object_iterator(iter);
-}
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
   }
-  return child;
+  return TAPE_ERROR;
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
-}
+#if SIMDJSON_DEVELOPMENT_CHECKS
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
 
 simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {

From e50f0537d94c232b26822615828cee15252382f8 Mon Sep 17 00:00:00 2001
From: Daniel Lemire <daniel@lemire.me>
Date: Sun, 19 Jan 2025 20:37:44 -0500
Subject: [PATCH 4/4] deps: update simdjson to 3.11.6

---
 deps/simdjson/simdjson.h | 78120 +++++++++++++++++--------------------
 1 file changed, 35272 insertions(+), 42848 deletions(-)

diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index 3589214b4584a0..7cdd3c87989e3b 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -49435,12 +49435,11 @@ simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::docume
 }
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
 simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
 template<typename T>
@@ -49520,7 +49519,7 @@ simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noex
 }
 simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -49559,7 +49558,7 @@ simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback
 
 simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
 simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
@@ -49575,12 +49574,12 @@ simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_d
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.raw_json_token();
 }
 
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.at_pointer(json_pointer);
 }
 
 simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
@@ -50043,1938 +50042,1628 @@ simdjson_inline document_stream::document_stream(
   if(worker.get() == nullptr) {
     error = MEMALLOC;
   }
+#endif
 }
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
 
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
-  }
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
-}
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
-}
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
-}
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
-}
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
-}
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
+}
 
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
+}
 
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-#endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
-}
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
   }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
 }
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
-}
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
-}
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
-}
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace fallback
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
-  fallback::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document>(
-      std::forward<fallback::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<fallback::ondemand::document>::simdjson_result(
+simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
   error_code error
 ) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document>(
-      error
-    )
+    implementation_simdjson_result_base<fallback::ondemand::document_stream>(error)
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
+  fallback::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::document_stream>(
+      std::forward<fallback::ondemand::document_stream>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for fallback */
+/* including simdjson/generic/ondemand/field-inl.h for fallback: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
+
 template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first).get<T>();
+
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first).get<T>(out);
+
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-template<> simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<fallback::ondemand::document> simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document>(first);
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
+  fallback::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::field>(
+      std::forward<fallback::ondemand::field>(value)
+    )
+{
 }
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<fallback::ondemand::document>::get<fallback::ondemand::document>(fallback::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<fallback::ondemand::document>(first);
-  return SUCCESS;
+simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<fallback::ondemand::field>(error)
+{
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document>::type() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return first.key();
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_scalar() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  return first.key_raw_json_token();
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.is_string();
+  return first.escaped_key();
 }
 
-simdjson_inline bool simdjson_result<fallback::ondemand::document>::is_negative() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.is_negative();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document>::is_integer() noexcept {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<fallback::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.is_integer();
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document>::get_number_type() noexcept {
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return first.get_number_type();
+  return std::move(first.value());
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+} // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for fallback */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, fallback::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document>::operator fallback::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
-#endif
 
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
 
-simdjson_inline bool simdjson_result<fallback::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
 
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
+}
 
-simdjson_inline int32_t simdjson_result<fallback::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
 
-} // namespace simdjson
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
+}
 
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
+}
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
+}
 
-namespace simdjson {
-namespace fallback {
-namespace ondemand {
-
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
-
-
-
-namespace simdjson {
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::simdjson_result(fallback::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<fallback::ondemand::document_reference>(std::forward<fallback::ondemand::document_reference>(value), error) {}
-
-
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<fallback::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<fallback::ondemand::array_iterator> simdjson_result<fallback::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<fallback::ondemand::array> simdjson_result<fallback::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object> simdjson_result<fallback::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<fallback::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<fallback::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<fallback::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<fallback::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
-template <class T>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<fallback::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
-simdjson_inline simdjson_result<fallback::ondemand::json_type> simdjson_result<fallback::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
-template <>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-template <>
-simdjson_inline error_code simdjson_result<fallback::ondemand::document_reference>::get(fallback::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<fallback::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<fallback::number_type> simdjson_result<fallback::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<fallback::ondemand::number> simdjson_result<fallback::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, fallback::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, fallback::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<fallback::ondemand::document_reference>::operator fallback::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
+
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
   }
-  return first.at_path(json_path);
+  return true;
 }
 
+} // namespace ondemand
+} // namespace fallback
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for fallback */
-/* including simdjson/generic/ondemand/document_stream-inl.h for fallback: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(fallback::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(std::forward<fallback::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/json_type-inl.h for fallback: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
-
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
-
-
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
-}
-
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
-
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
 #endif
-}
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
-}
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
-}
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
   }
-}
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
-}
-
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
-}
-
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  if(is_int64()) {
+    return double(payload.signed_integer);
   }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
-}
-
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
-
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
-
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
-
 } // namespace ondemand
 } // namespace fallback
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document_stream>(error)
-{
-}
-simdjson_inline simdjson_result<fallback::ondemand::document_stream>::simdjson_result(
-  fallback::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::document_stream>(
-      std::forward<fallback::ondemand::document_stream>(value)
-    )
-{
-}
+simdjson_inline simdjson_result<fallback::ondemand::json_type>::simdjson_result(fallback::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_type>(std::forward<fallback::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::json_type>(error) {}
 
-}
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for fallback */
-/* including simdjson/generic/ondemand/field-inl.h for fallback: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for fallback */
+/* including simdjson/generic/ondemand/logger-inl.h for fallback: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+#include <cstring>
+
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
+namespace logger {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
-  return true;
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return true;
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
 
-} // namespace ondemand
-} // namespace fallback
-} // namespace simdjson
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+}
 
-namespace simdjson {
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+}
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+}
 
-simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
-  fallback::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::field>(
-      std::forward<fallback::ondemand::field>(value)
-    )
-{
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
-simdjson_inline simdjson_result<fallback::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<fallback::ondemand::field>(error)
-{
+
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::raw_json_string> simdjson_result<fallback::ondemand::field>::key() noexcept {
-  if (error()) { return error(); }
-  return first.key();
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::key_raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.key_raw_json_token();
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::escaped_key() noexcept {
-  if (error()) { return error(); }
-  return first.escaped_key();
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<fallback::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
+
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<fallback::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
 
-simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::field>::value() noexcept {
-  if (error()) { return error(); }
-  return std::move(first.value());
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
+} // namespace logger
+} // namespace ondemand
+} // namespace fallback
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for fallback */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for fallback */
+/* including simdjson/generic/ondemand/object-inl.h for fallback: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
 
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
+}
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
+}
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
 
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
+}
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
 
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
       }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
   }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
-}
-
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
-}
+} // namespace ondemand
+} // namespace fallback
+} // namespace simdjson
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
-}
+namespace simdjson {
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
+simdjson_inline simdjson_result<fallback::ondemand::object>::simdjson_result(fallback::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::object>(std::forward<fallback::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::object>(error) {}
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator> simdjson_result<fallback::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator> simdjson_result<fallback::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
 }
-
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::object>(first).find_field_unordered(key);
 }
-
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::object>(first)[key];
 }
-
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<fallback::ondemand::object>(first).find_field(key);
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+simdjson_inline simdjson_result<fallback::ondemand::value> simdjson_result<fallback::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+inline simdjson_result<bool> simdjson_result<fallback::ondemand::object>::reset() noexcept {
+  if (error()) { return error(); }
+  return first.reset();
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+inline simdjson_result<bool> simdjson_result<fallback::ondemand::object>::is_empty() noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline  simdjson_result<size_t> simdjson_result<fallback::ondemand::object>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
 
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<fallback::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
+} // namespace simdjson
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for fallback */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
-}
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
-}
+//
+// object_iterator
+//
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
-}
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
   return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
-}
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
-}
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
 }
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
 }
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
-#endif
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
 } // namespace ondemand
 } // namespace fallback
@@ -51982,239 +51671,168 @@ simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const ui
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(fallback::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(std::forward<fallback::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::json_iterator>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
+  fallback::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
+/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace fallback {
 namespace ondemand {
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+  }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+}
 #endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-  return true;
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-  return SUCCESS;
+
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
+}
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
-
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
-
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-
-  // If the loop ended, we're out of fields to look at.
-  return false;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
+}
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
 simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
   if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
@@ -52458,62 +52076,28 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
   return !(a == c);
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
+}
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
+}
 
 } // namespace ondemand
 } // namespace fallback
@@ -52521,272 +52105,343 @@ SIMDJSON_POP_DISABLE_WARNINGS
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(
-  fallback::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>(std::forward<fallback::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<fallback::ondemand::object_iterator>({}, error)
-{
-}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(fallback::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(std::forward<fallback::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::raw_json_string>(error) {}
 
-simdjson_inline simdjson_result<fallback::ondemand::field> simdjson_result<fallback::ondemand::object_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<fallback::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator==(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+  return first.raw();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<fallback::ondemand::object_iterator>::operator!=(const simdjson_result<fallback::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<fallback::ondemand::object_iterator> &simdjson_result<fallback::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<fallback::ondemand::raw_json_string>::unescape_wobbly(fallback::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for fallback */
-/* including simdjson/generic/ondemand/parser-inl.h for fallback: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for fallback */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for fallback */
+/* including simdjson/generic/ondemand/serialization-inl.h for fallback: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-namespace fallback {
-namespace ondemand {
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace fallback::ondemand;
+  fallback::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      fallback::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      fallback::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
   }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+inline simdjson_result<std::string_view> to_json_string(fallback::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<fallback::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
+namespace simdjson { namespace fallback { namespace ondemand {
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
-
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
   }
-  return result;
 }
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
+#endif
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
   } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+    throw simdjson::simdjson_error(error);
   }
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::fallback::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
+}
+#endif
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::fallback::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::fallback::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
+}
+#endif
+}}} // namespace simdjson::fallback::ondemand
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for fallback */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for fallback: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for fallback */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace fallback {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
+}
+
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
+}
+
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
+}
+
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
+}
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
+}
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
+}
+
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
+}
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
+}
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
+}
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
+}
+
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
+}
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
+}
+
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
+}
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
+}
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
+}
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
+}
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
+}
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
 } // namespace ondemand
@@ -52795,10 +52450,10 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(fallback::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(std::forward<fallback::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<fallback::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(fallback::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(std::forward<fallback::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<fallback::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<fallback::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
@@ -52820,7 +52475,6 @@ simdjson_inline simdjson_result<fallback::ondemand::parser>::simdjson_result(err
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-
 namespace fallback {
 namespace ondemand {
 
@@ -52900,7 +52554,6 @@ simdjson_warn_unused simdjson_inline error_code value_iterator::end_container()
     _json_iter->ascend_to(depth()-1);
     return SUCCESS;
 }
-} // namespace simdjson
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
   assert_at_next();
@@ -53031,49 +52684,20 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_
   // If we don't find a match, we may loop back around, and scan from the beginning to that point.
   token_position search_start = _json_iter->position();
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for fallback */
-
-
-/* end file simdjson/generic/ondemand/amalgamated.h for fallback */
-/* including simdjson/fallback/end.h: #include "simdjson/fallback/end.h" */
-/* begin file simdjson/fallback/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/fallback/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-/* undefining SIMDJSON_IMPLEMENTATION from "fallback" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/fallback/end.h */
-
-#endif // SIMDJSON_FALLBACK_ONDEMAND_H
-/* end file simdjson/fallback/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
-/* including simdjson/haswell/ondemand.h: #include "simdjson/haswell/ondemand.h" */
-/* begin file simdjson/haswell/ondemand.h */
-#ifndef SIMDJSON_HASWELL_ONDEMAND_H
-#define SIMDJSON_HASWELL_ONDEMAND_H
-
-/* including simdjson/haswell/begin.h: #include "simdjson/haswell/begin.h" */
-/* begin file simdjson/haswell/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "haswell" */
-#define SIMDJSON_IMPLEMENTATION haswell
-
-/* including simdjson/haswell/base.h: #include "simdjson/haswell/base.h" */
-/* begin file simdjson/haswell/base.h */
-#ifndef SIMDJSON_HASWELL_BASE_H
-#define SIMDJSON_HASWELL_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_HASWELL
-namespace simdjson {
-/**
- * Implementation for Haswell (Intel AVX2).
- */
-namespace haswell {
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
   // 2. When a previous search did not yield a value or the object is empty:
   //
@@ -53212,15 +52836,27 @@ namespace haswell {
       return true;
     }
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
-// We enable bmi2 only if LLVM/clang is used, because GCC may not
-// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
-#if defined(__clang__)
-SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
-#else
-SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
-#endif
-#endif
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
+  }
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
 simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
   assert_at_next();
@@ -55418,137 +55054,13 @@ class value {
    */
   simdjson_inline simdjson_result<array> get_array() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for haswell */
-/* including simdjson/generic/ondemand/deserialize.h for haswell: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for haswell */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-namespace simdjson {
-
-namespace tag_invoke_fn_ns {
-void tag_invoke();
-
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
-
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
-
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
-
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
-
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
-
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
-
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
-
-
-struct deserialize_tag;
-
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<haswell::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<haswell::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<haswell::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<haswell::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
-
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
-
-template <typename T, typename ValT = haswell::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
-
-template <typename T, typename ValT = haswell::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-template <typename T, typename ValT = haswell::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
-
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = haswell::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = haswell::ondemand::value;
-  using document_type = haswell::ondemand::document;
-  using document_reference_type = haswell::ondemand::document_reference;
-
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-
-} deserialize{};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for haswell */
-/* including simdjson/generic/ondemand/value_iterator.h for haswell: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
   /**
    * Cast this JSON value to an unsigned integer.
@@ -56501,16 +56013,13 @@ struct simdjson_result<haswell::ondemand::token_iterator> : public haswell::impl
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <type_traits>
-
 namespace simdjson {
-
 namespace haswell {
 namespace ondemand {
+
 /**
  * Iterates through JSON tokens, keeping track of depth and string buffer.
  *
@@ -56545,50 +56054,32 @@ class json_iterator {
    * - 2 = , or } inside root array/object
    * - 3 = key or value inside root array/object.
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-
+  depth_t _depth{};
+  /**
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
+   */
+  token_position _root{};
+  /**
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
+   */
+  bool _streaming{false};
 
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
    * Skips a JSON value, whether it is a scalar, array or object.
    */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
   /**
    * Tell whether the iterator is still at the start
@@ -56661,20 +56152,10 @@ class json_iterator {
    *
    * This is not null-terminated; it is a view into the JSON.
    *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
   simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
@@ -56959,15 +56440,19 @@ struct number {
    * functions on a number type. They are protected and should never be used outside
    * of the core simdjson library.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
-
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
   /**
    * End of friend declarations.
    */
@@ -57190,14 +56675,13 @@ class raw_json_string {
    *
    * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<haswell::ondemand::value> operator[](int) noexcept = delete;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
+  friend class object;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
+};
 
 simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
 
@@ -58228,25 +57712,12 @@ class document {
   /**
    * Cast this JSON value to an array.
    *
-   * ### std::string references
-   *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
-   *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
-   *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
-   *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() & noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
    * @returns An object that can be used to look up or iterate fields.
    * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
@@ -58471,13 +57942,43 @@ class document {
    *
    * @returns true if the number if negative.
    */
-  bool threaded{true};
-  #else
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
   /**
    * Attempt to parse an ondemand::number. An ondemand::number may
    * contain an integer value or a floating-point value, the simdjson
@@ -58547,19 +58048,7 @@ class document {
   inline bool is_alive() noexcept;
 
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * Returns the current location in the document if in bounds.
    */
   inline simdjson_result<const char *> current_location() const noexcept;
 
@@ -58991,11 +58480,16 @@ struct simdjson_result<haswell::ondemand::document_reference> : public haswell::
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
 
 namespace simdjson {
 namespace haswell {
@@ -59100,74 +58594,92 @@ class document_stream {
    *   size_t truncated = stream.truncated_bytes();
    *
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+  inline size_t truncated_bytes() const noexcept;
+
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
+
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
+
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
+
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
+
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
+
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
 
   /**
    * Start iterating the documents in the stream.
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
-
-#if SIMDJSON_EXCEPTIONS
+  simdjson_inline iterator begin() noexcept;
   /**
    * The end of the stream, for iterator comparison purposes.
    */
@@ -59361,16 +58873,10 @@ class field : public std::pair<raw_json_string, value> {
    */
   simdjson_inline raw_json_string key() const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
    */
   simdjson_inline std::string_view key_raw_json_token() const noexcept;
   /**
@@ -59533,171 +59039,7 @@ class object {
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
   /**
    * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -59813,148 +59155,6 @@ class object {
   friend struct simdjson_result<object>;
 };
 
-
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-private:
-  document *doc{nullptr};
-};
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
@@ -59971,10 +59171,7 @@ struct simdjson_result<haswell::ondemand::object> : public haswell::implementati
   simdjson_inline simdjson_result<haswell::ondemand::object_iterator> begin() noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::object_iterator> end() noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
@@ -60058,64 +59255,9 @@ struct simdjson_result<haswell::ondemand::object_iterator> : public haswell::imp
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
 
-  simdjson_inline simdjson_result<haswell::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator haswell::ondemand::array() & noexcept(false);
-  simdjson_inline operator haswell::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator haswell::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator haswell::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<haswell::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<haswell::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<haswell::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  //
+  // Iterator interface
+  //
 
   // Reads key and value, yielding them to the user.
   simdjson_inline simdjson_result<haswell::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
@@ -60948,10 +60090,74 @@ simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number()
   return iter.get_number();
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
+
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
+
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
+
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
 simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
@@ -61219,3275 +60425,3147 @@ simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswel
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for haswell */
+/* including simdjson/generic/ondemand/document-inl.h for haswell: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
 {
+  logger::log_start_value(iter, "document");
 }
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
+
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
 }
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
+
+inline void document::rewind() noexcept {
+  iter.rewind();
 }
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
 }
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
+
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
 }
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
+
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
+}
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
+}
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
+}
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
+}
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
+}
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
     return get_object();
   } else {
-    return object::resume(iter);
+    return object::resume(resume_value_iterator());
   }
 }
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
 }
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for haswell: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for haswell */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-#include <concepts>
-#include <limits>
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
-namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
 
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
+}
 
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
   }
-  out = static_cast<T>(x);
-  return SUCCESS;
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
 
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-  haswell::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
 }
 
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
 
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
 
-/**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
- *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
- *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
+}
 
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
 
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+}
+
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
   }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
 }
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  if (!out) {
-    out.emplace();
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
 }
 
+} // namespace ondemand
+} // namespace haswell
 } // namespace simdjson
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for haswell */
-
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for haswell: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+namespace simdjson {
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
+simdjson_inline simdjson_result<haswell::ondemand::document>::simdjson_result(
+  haswell::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document>(
+      std::forward<haswell::ondemand::document>(value)
+    )
+{
 }
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
+simdjson_inline simdjson_result<haswell::ondemand::document>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document>(
+      error
+    )
+{
 }
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline error_code simdjson_result<haswell::ondemand::document>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document>::end() & noexcept {
   return {};
 }
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
+template<typename T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document>(first).get<T>(out);
+}
 
-template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
+template<> simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<haswell::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<haswell::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<haswell::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
+
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
+template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
+simdjson_inline bool simdjson_result<haswell::ondemand::document>::at_end() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.at_end();
 }
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
+
+simdjson_inline int32_t simdjson_result<haswell::ondemand::document>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/value-inl.h for haswell: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
 template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
 #endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
 
+
+
 namespace simdjson {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::simdjson_result(haswell::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<haswell::ondemand::document_reference>(std::forward<haswell::ondemand::document_reference>(value), error) {}
 
-simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
-  haswell::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::value>(
-      std::forward<haswell::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<haswell::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::value>::end() & noexcept {
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::rewind() noexcept {
   if (error()) { return error(); }
-  return {};
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.begin();
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::value>::get_array() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document_reference>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::value>::get_object() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document_reference>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document_reference>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>(haswell::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<haswell::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-
-template<> simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::get<haswell::ondemand::value>() noexcept  {
+template <class T>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<haswell::ondemand::document_reference>(first).get<T>(out);
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_string() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_negative() noexcept {
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::value>::is_integer() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::value>::get_number_type() noexcept {
+simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document_reference>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::value>::get_number() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document_reference>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator T() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, haswell::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, haswell::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
   return first.get<T>();
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator haswell::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::value>::current_location() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document_reference>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<haswell::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
   if (error()) {
-    return error();
+      return error();
   }
   return first.at_path(json_path);
 }
 
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for haswell */
-/* including simdjson/generic/ondemand/document-inl.h for haswell: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for haswell */
+/* including simdjson/generic/ondemand/document_stream-inl.h for haswell: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
-{
-  logger::log_start_value(iter, "document");
-}
-
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
-}
-
-inline void document::rewind() noexcept {
-  iter.rewind();
-}
+#include <algorithm>
+#include <stdexcept>
 
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
-}
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
 
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
-}
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
-}
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
-}
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
-    return get_object();
-  } else {
-    return object::resume(resume_value_iterator());
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
   }
-}
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
-
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
     }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
-  }
-}
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
-}
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+  );
 }
 
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
-}
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
-}
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
-}
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
-}
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
-}
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
-}
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
-
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
-
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+#endif  // SIMDJSON_THREADS_ENABLED
 
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
 #endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
-  }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
 
-
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
   }
-}
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
   }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-simdjson_inline simdjson_result<haswell::ondemand::document>::simdjson_result(
-  haswell::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document>(
-      std::forward<haswell::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document>(
-      error
-    )
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<haswell::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
+
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+
+#endif // SIMDJSON_THREADS_ENABLED
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document_stream>(error)
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
+  haswell::ondemand::document_stream &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::document_stream>(
+      std::forward<haswell::ondemand::document_stream>(value)
+    )
+{
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first).get<T>();
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for haswell */
+/* including simdjson/generic/ondemand/field-inl.h for haswell: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first).get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-template<> simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<haswell::ondemand::document>(first);
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
   return SUCCESS;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_inline bool simdjson_result<haswell::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
+namespace simdjson {
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
+  haswell::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::field>(
+      std::forward<haswell::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<haswell::ondemand::field>(error)
+{
 }
-#endif
-
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document>::current_location() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  return first.key();
 }
 
-simdjson_inline bool simdjson_result<haswell::ondemand::document>::at_end() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.at_end();
+  return first.key_raw_json_token();
 }
 
-
-simdjson_inline int32_t simdjson_result<haswell::ondemand::document>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.escaped_key();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first).get<T>();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<haswell::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return std::move(first.value());
 }
 
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for haswell */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
+}
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
+}
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
+}
 
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
 
-namespace simdjson {
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::simdjson_result(haswell::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<haswell::ondemand::document_reference>(std::forward<haswell::ondemand::document_reference>(value), error) {}
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
+}
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
+}
 
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::end() & noexcept {
-  return {};
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-template <>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-template <>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, haswell::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, haswell::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
+
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
   }
-  return first.at_path(json_path);
+  return true;
 }
 
+} // namespace ondemand
+} // namespace haswell
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for haswell */
-/* including simdjson/generic/ondemand/document_stream-inl.h for haswell: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(haswell::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(std::forward<haswell::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/json_type-inl.h for haswell: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
+#endif
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
 
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
-template<typename T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first).get<T>(out);
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-template<> simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<haswell::ondemand::document> simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<haswell::ondemand::document>::get<haswell::ondemand::document>(haswell::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<haswell::ondemand::document>(first);
-  return SUCCESS;
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
-simdjson_inline bool simdjson_result<haswell::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
+simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(haswell::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_type>(std::forward<haswell::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::json_type>(error) {}
 
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
+} // namespace simdjson
 
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for haswell */
+/* including simdjson/generic/ondemand/logger-inl.h for haswell: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+#include <cstring>
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, haswell::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+namespace logger {
+
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
+  }
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<haswell::ondemand::document>::operator haswell::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-#endif
-
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_inline bool simdjson_result<haswell::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+}
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
 
-
-simdjson_inline int32_t simdjson_result<haswell::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-} // namespace simdjson
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+}
 
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
+} // namespace logger
 } // namespace ondemand
 } // namespace haswell
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for haswell */
+/* including simdjson/generic/ondemand/object-inl.h for haswell: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::simdjson_result(haswell::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<haswell::ondemand::document_reference>(std::forward<haswell::ondemand::document_reference>(value), error) {}
-
+namespace haswell {
+namespace ondemand {
 
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<haswell::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<haswell::ondemand::array_iterator> simdjson_result<haswell::ondemand::document_reference>::end() & noexcept {
-  return {};
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
-simdjson_inline simdjson_result<haswell::ondemand::array> simdjson_result<haswell::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
-simdjson_inline simdjson_result<haswell::ondemand::object> simdjson_result<haswell::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<haswell::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<haswell::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
-simdjson_inline simdjson_result<double> simdjson_result<haswell::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(haswell::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::object>(std::forward<haswell::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::begin() noexcept {
   if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+  return first.begin();
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::end() noexcept {
   if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+  return first.end();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.get_wobbly_string();
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::document_reference>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_raw_json_string();
+  return std::forward<haswell::ondemand::object>(first).find_field_unordered(key);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::get_bool() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.get_bool();
+  return first[key];
 }
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::get_value() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_value();
+  return std::forward<haswell::ondemand::object>(first)[key];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_null() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.find_field(key);
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() & noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  return std::forward<haswell::ondemand::object>(first).find_field(key);
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<haswell::ondemand::document_reference>::get() && noexcept {
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document_reference>(first).get<T>();
+  return first.at_pointer(json_pointer);
 }
-template <class T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
-template <class T>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(T &out) && noexcept {
+
+inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return std::forward<haswell::ondemand::document_reference>(first).get<T>(out);
+  return first.reset();
 }
-simdjson_inline simdjson_result<haswell::ondemand::json_type> simdjson_result<haswell::ondemand::document_reference>::type() noexcept {
+
+inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return first.is_empty();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_scalar() noexcept {
+
+simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  return first.count_fields();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_string() noexcept {
+
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::object>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first.is_string();
+  return first.raw_json();
 }
-template <>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-template <>
-simdjson_inline error_code simdjson_result<haswell::ondemand::document_reference>::get(haswell::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<haswell::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<haswell::number_type> simdjson_result<haswell::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<haswell::ondemand::number> simdjson_result<haswell::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, haswell::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, haswell::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for haswell */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
+
+//
+// object_iterator
+//
+
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
+
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+SIMDJSON_POP_DISABLE_WARNINGS
+
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
+
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
+  haswell::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_reference>::operator haswell::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
+{
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::document_reference>::current_location() noexcept {
+simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return *first;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
+// Checks for ']' and ','
+simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for haswell */
-/* including simdjson/generic/ondemand/document_stream-inl.h for haswell: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
+}
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-#endif
-}
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
   }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+}
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
+namespace simdjson {
+
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for haswell */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for haswell: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+namespace haswell {
+namespace ondemand {
+
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
+  return true;
 }
 
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
+  if(r[pos] != '"') { return false; }
+  return true;
+}
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
     }
-    if (depth == 0) { break; }
-    cur_struct_index++;
   }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
+}
 
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
+}
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
-  }
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
 
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
+}
+
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
+}
 
 } // namespace ondemand
 } // namespace haswell
@@ -64495,1162 +63573,1439 @@ inline void document_stream::start_stage1_thread() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document_stream>(error)
-{
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(haswell::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(std::forward<haswell::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<haswell::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-simdjson_inline simdjson_result<haswell::ondemand::document_stream>::simdjson_result(
-  haswell::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::document_stream>(
-      std::forward<haswell::ondemand::document_stream>(value)
-    )
-{
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<haswell::ondemand::raw_json_string>::unescape_wobbly(haswell::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for haswell */
-/* including simdjson/generic/ondemand/field-inl.h for haswell: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for haswell */
+/* including simdjson/generic/ondemand/serialization-inl.h for haswell: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-namespace haswell {
-namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
-
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
-}
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace haswell::ondemand;
+  haswell::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      haswell::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      haswell::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
+inline simdjson_result<std::string_view> to_json_string(haswell::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
+}
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-} // namespace ondemand
-} // namespace haswell
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<haswell::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
+}
 } // namespace simdjson
 
-namespace simdjson {
+namespace simdjson { namespace haswell { namespace ondemand {
 
-simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
-  haswell::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::field>(
-      std::forward<haswell::ondemand::field>(value)
-    )
-{
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline simdjson_result<haswell::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<haswell::ondemand::field>(error)
-{
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::raw_json_string> simdjson_result<haswell::ondemand::field>::key() noexcept {
-  if (error()) { return error(); }
-  return first.key();
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::key_raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.key_raw_json_token();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::escaped_key() noexcept {
-  if (error()) { return error(); }
-  return first.escaped_key();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<haswell::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<haswell::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::field>::value() noexcept {
-  if (error()) { return error(); }
-  return std::move(first.value());
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::haswell::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-} // namespace simdjson
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::haswell::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::haswell::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
+}
+#endif
+}}} // namespace simdjson::haswell::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for haswell */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for haswell */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace haswell {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
 {
-  other.parser = nullptr;
-}
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
 }
 
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
+} // namespace ondemand
+} // namespace haswell
+} // namespace simdjson
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
+namespace simdjson {
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
+simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(haswell::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(std::forward<haswell::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::token_iterator>(error) {}
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
+} // namespace simdjson
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
-}
+namespace simdjson {
+namespace haswell {
+namespace ondemand {
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
 }
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
+
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
 #endif
-}
+    return false;
 
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
 #if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  token.set_position(position);
-  _depth = child_depth;
-}
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
   }
-  return TAPE_ERROR;
-}
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
 
-#endif
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
 
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
-}
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
   }
-  return true;
-}
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(haswell::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(std::forward<haswell::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_iterator>(error) {}
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-} // namespace simdjson
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/json_type-inl.h for haswell: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
-    return out;
-}
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
+  }
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
-#endif
-
+SIMDJSON_POP_DISABLE_WARNINGS
 
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
-}
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
 }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
+  }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  return true;
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    }
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
 }
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
   }
-  return double(payload.unsigned_integer);
 }
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
 }
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
 }
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
 }
-
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
+}
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
+}
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
+  if(error) { return error; }
+  return num;
 }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-namespace simdjson {
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+  }
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
+}
 
-simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(haswell::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_type>(std::forward<haswell::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<haswell::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
+}
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
+  if(error) { return error; }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
+}
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-} // namespace simdjson
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for haswell */
-/* including simdjson/generic/ondemand/logger-inl.h for haswell: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
+}
 
-#include <memory>
-#include <cstring>
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
 
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
-namespace logger {
+  return _json_iter->skip_child(depth());
+}
 
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
+}
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
+}
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
+}
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
+}
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
+}
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
 }
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
+
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
 }
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
+
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+  } else {
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
+  }
+
+
+  return SUCCESS;
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
+
+  assert_at_root();
+  return _json_iter->peek();
 }
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
+
+  assert_at_non_root_start();
+  return _json_iter->peek();
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
+
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
 }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
 }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-} // namespace logger
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for haswell */
-/* including simdjson/generic/ondemand/object-inl.h for haswell: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace haswell {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
 }
 
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
 }
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
+}
 
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
   }
-  return child;
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
 }
 
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
+}
+
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
 }
 
 } // namespace ondemand
@@ -65659,2430 +65014,2306 @@ simdjson_inline simdjson_result<bool> object::reset() & noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(haswell::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::object>(std::forward<haswell::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::object>(error) {}
+simdjson_inline simdjson_result<haswell::ondemand::value_iterator>::simdjson_result(haswell::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::value_iterator>(std::forward<haswell::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<haswell::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<haswell::ondemand::value_iterator>(error) {}
 
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> simdjson_result<haswell::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first)[key];
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<haswell::ondemand::object>(first).find_field(key);
-}
+} // namespace simdjson
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
 
-simdjson_inline simdjson_result<haswell::ondemand::value> simdjson_result<haswell::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
 
-inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
-}
+/* end file simdjson/generic/ondemand/amalgamated.h for haswell */
+/* including simdjson/haswell/end.h: #include "simdjson/haswell/end.h" */
+/* begin file simdjson/haswell/end.h */
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/haswell/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline simdjson_result<bool> simdjson_result<haswell::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
+#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
+SIMDJSON_UNTARGET_REGION
+#endif
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<haswell::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
+/* undefining SIMDJSON_IMPLEMENTATION from "haswell" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/haswell/end.h */
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<haswell::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-} // namespace simdjson
+#endif // SIMDJSON_HASWELL_ONDEMAND_H
+/* end file simdjson/haswell/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
+/* including simdjson/icelake/ondemand.h: #include "simdjson/icelake/ondemand.h" */
+/* begin file simdjson/icelake/ondemand.h */
+#ifndef SIMDJSON_ICELAKE_ONDEMAND_H
+#define SIMDJSON_ICELAKE_ONDEMAND_H
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for haswell */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* including simdjson/icelake/begin.h: #include "simdjson/icelake/begin.h" */
+/* begin file simdjson/icelake/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "icelake" */
+#define SIMDJSON_IMPLEMENTATION icelake
+/* including simdjson/icelake/base.h: #include "simdjson/icelake/base.h" */
+/* begin file simdjson/icelake/base.h */
+#ifndef SIMDJSON_ICELAKE_BASE_H
+#define SIMDJSON_ICELAKE_BASE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_ICELAKE
 namespace simdjson {
-namespace haswell {
-namespace ondemand {
+/**
+ * Implementation for Icelake (Intel AVX512).
+ */
+namespace icelake {
 
-//
-// object_iterator
-//
+class implementation;
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+} // namespace icelake
+} // namespace simdjson
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
+#endif // SIMDJSON_ICELAKE_BASE_H
+/* end file simdjson/icelake/base.h */
+/* including simdjson/icelake/intrinsics.h: #include "simdjson/icelake/intrinsics.h" */
+/* begin file simdjson/icelake/intrinsics.h */
+#ifndef SIMDJSON_ICELAKE_INTRINSICS_H
+#define SIMDJSON_ICELAKE_INTRINSICS_H
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
+#if SIMDJSON_VISUAL_STUDIO
+// under clang within visual studio, this will include <x86intrin.h>
+#include <intrin.h>  // visual studio or clang
+#else
+#include <x86intrin.h> // elsewhere
+#endif // SIMDJSON_VISUAL_STUDIO
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+#if SIMDJSON_CLANG_VISUAL_STUDIO
+/**
+ * You are not supposed, normally, to include these
+ * headers directly. Instead you should either include intrin.h
+ * or x86intrin.h. However, when compiling with clang
+ * under Windows (i.e., when _MSC_VER is set), these headers
+ * only get included *if* the corresponding features are detected
+ * from macros:
+ * e.g., if __AVX2__ is set... in turn,  we normally set these
+ * macros by compiling against the corresponding architecture
+ * (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole
+ * software with these advanced instructions. In simdjson, we
+ * want to compile the whole program for a generic target,
+ * and only target our specific kernels. As a workaround,
+ * we directly include the needed headers. These headers would
+ * normally guard against such usage, but we carefully included
+ * <x86intrin.h>  (or <intrin.h>) before, so the headers
+ * are fooled.
+ */
+#include <bmiintrin.h>   // for _blsr_u64
+#include <lzcntintrin.h> // for  __lzcnt64
+#include <immintrin.h>   // for most things (AVX2, AVX512, _popcnt64)
+#include <smmintrin.h>
+#include <tmmintrin.h>
+#include <avxintrin.h>
+#include <avx2intrin.h>
+#include <wmmintrin.h>   // for  _mm_clmulepi64_si128
+// Important: we need the AVX-512 headers:
+#include <avx512fintrin.h>
+#include <avx512dqintrin.h>
+#include <avx512cdintrin.h>
+#include <avx512bwintrin.h>
+#include <avx512vlintrin.h>
+#include <avx512vbmiintrin.h>
+#include <avx512vbmi2intrin.h>
+// unfortunately, we may not get _blsr_u64, but, thankfully, clang
+// has it as a macro.
+#ifndef _blsr_u64
+// we roll our own
+#define _blsr_u64(n) ((n - 1) & n)
+#endif //  _blsr_u64
+#endif // SIMDJSON_CLANG_VISUAL_STUDIO
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+static_assert(sizeof(__m512i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for icelake");
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+#endif // SIMDJSON_ICELAKE_INTRINSICS_H
+/* end file simdjson/icelake/intrinsics.h */
+
+#if !SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
+SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt,popcnt")
+#endif
+
+/* including simdjson/icelake/bitmanipulation.h: #include "simdjson/icelake/bitmanipulation.h" */
+/* begin file simdjson/icelake/bitmanipulation.h */
+#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
+#define SIMDJSON_ICELAKE_BITMANIPULATION_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace icelake {
+namespace {
 
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(
-  haswell::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>(std::forward<haswell::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  return (int)_tzcnt_u64(input_num);
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO
+  ////////
+  // You might expect the next line to be equivalent to
+  // return (int)_tzcnt_u64(input_num);
+  // but the generated code differs and might be less efficient?
+  ////////
+  return __builtin_ctzll(input_num);
+#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
 }
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<haswell::ondemand::object_iterator>({}, error)
-{
+
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return _blsr_u64(input_num);
 }
 
-simdjson_inline simdjson_result<haswell::ondemand::field> simdjson_result<haswell::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+  return int(_lzcnt_u64(input_num));
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator==(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
+  // note: we do not support legacy 32-bit Windows
+  return __popcnt64(input_num);// Visual Studio wants two underscores
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<haswell::ondemand::object_iterator>::operator!=(const simdjson_result<haswell::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+#else
+simdjson_inline long long int count_ones(uint64_t input_num) {
+  return _popcnt64(input_num);
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<haswell::ondemand::object_iterator> &simdjson_result<haswell::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+#endif
+
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
+                                uint64_t *result) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  return _addcarry_u64(0, value1, value2,
+                       reinterpret_cast<unsigned __int64 *>(result));
+#else
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
+#endif
 }
 
+} // unnamed namespace
+} // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/parser-inl.h for haswell: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
+/* end file simdjson/icelake/bitmanipulation.h */
+/* including simdjson/icelake/bitmask.h: #include "simdjson/icelake/bitmask.h" */
+/* begin file simdjson/icelake/bitmask.h */
+#ifndef SIMDJSON_ICELAKE_BITMASK_H
+#define SIMDJSON_ICELAKE_BITMASK_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-namespace haswell {
-namespace ondemand {
+namespace icelake {
+namespace {
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
+  // There should be no such thing with a processor supporting avx2
+  // but not clmul.
+  __m128i all_ones = _mm_set1_epi8('\xFF');
+  __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
+  return _mm_cvtsi128_si64(result);
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
+} // unnamed namespace
+} // namespace icelake
+} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+#endif // SIMDJSON_ICELAKE_BITMASK_H
+/* end file simdjson/icelake/bitmask.h */
+/* including simdjson/icelake/simd.h: #include "simdjson/icelake/simd.h" */
+/* begin file simdjson/icelake/simd.h */
+#ifndef SIMDJSON_ICELAKE_SIMD_H
+#define SIMDJSON_ICELAKE_SIMD_H
 
-  json.remove_utf8_bom();
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+#if defined(__GNUC__) && !defined(__clang__)
+#if __GNUC__ == 8
+#define SIMDJSON_GCC8 1
+#endif //  __GNUC__ == 8
+#endif // defined(__GNUC__) && !defined(__clang__)
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+#if SIMDJSON_GCC8
+/**
+ * GCC 8 fails to provide _mm512_set_epi8. We roll our own.
+ */
+inline __m512i _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8, uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12, uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16, uint8_t a17, uint8_t a18, uint8_t a19, uint8_t a20, uint8_t a21, uint8_t a22, uint8_t a23, uint8_t a24, uint8_t a25, uint8_t a26, uint8_t a27, uint8_t a28, uint8_t a29, uint8_t a30, uint8_t a31, uint8_t a32, uint8_t a33, uint8_t a34, uint8_t a35, uint8_t a36, uint8_t a37, uint8_t a38, uint8_t a39, uint8_t a40, uint8_t a41, uint8_t a42, uint8_t a43, uint8_t a44, uint8_t a45, uint8_t a46, uint8_t a47, uint8_t a48, uint8_t a49, uint8_t a50, uint8_t a51, uint8_t a52, uint8_t a53, uint8_t a54, uint8_t a55, uint8_t a56, uint8_t a57, uint8_t a58, uint8_t a59, uint8_t a60, uint8_t a61, uint8_t a62, uint8_t a63) {
+  return _mm512_set_epi64(uint64_t(a7) + (uint64_t(a6) << 8) + (uint64_t(a5) << 16) + (uint64_t(a4) << 24) + (uint64_t(a3) << 32) + (uint64_t(a2) << 40) + (uint64_t(a1) << 48) + (uint64_t(a0) << 56),
+                          uint64_t(a15) + (uint64_t(a14) << 8) + (uint64_t(a13) << 16) + (uint64_t(a12) << 24) + (uint64_t(a11) << 32) + (uint64_t(a10) << 40) + (uint64_t(a9) << 48) + (uint64_t(a8) << 56),
+                          uint64_t(a23) + (uint64_t(a22) << 8) + (uint64_t(a21) << 16) + (uint64_t(a20) << 24) + (uint64_t(a19) << 32) + (uint64_t(a18) << 40) + (uint64_t(a17) << 48) + (uint64_t(a16) << 56),
+                          uint64_t(a31) + (uint64_t(a30) << 8) + (uint64_t(a29) << 16) + (uint64_t(a28) << 24) + (uint64_t(a27) << 32) + (uint64_t(a26) << 40) + (uint64_t(a25) << 48) + (uint64_t(a24) << 56),
+                          uint64_t(a39) + (uint64_t(a38) << 8) + (uint64_t(a37) << 16) + (uint64_t(a36) << 24) + (uint64_t(a35) << 32) + (uint64_t(a34) << 40) + (uint64_t(a33) << 48) + (uint64_t(a32) << 56),
+                          uint64_t(a47) + (uint64_t(a46) << 8) + (uint64_t(a45) << 16) + (uint64_t(a44) << 24) + (uint64_t(a43) << 32) + (uint64_t(a42) << 40) + (uint64_t(a41) << 48) + (uint64_t(a40) << 56),
+                          uint64_t(a55) + (uint64_t(a54) << 8) + (uint64_t(a53) << 16) + (uint64_t(a52) << 24) + (uint64_t(a51) << 32) + (uint64_t(a50) << 40) + (uint64_t(a49) << 48) + (uint64_t(a48) << 56),
+                          uint64_t(a63) + (uint64_t(a62) << 8) + (uint64_t(a61) << 16) + (uint64_t(a60) << 24) + (uint64_t(a59) << 32) + (uint64_t(a58) << 40) + (uint64_t(a57) << 48) + (uint64_t(a56) << 56));
 }
+#endif // SIMDJSON_GCC8
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+namespace simdjson {
+namespace icelake {
+namespace {
+namespace simd {
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  // Forward-declared so they can be used by splat and friends.
+  template<typename Child>
+  struct base {
+    __m512i value;
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
+    // Zero constructor
+    simdjson_inline base() : value{__m512i()} {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
+    // Conversion from SIMD register
+    simdjson_inline base(const __m512i _value) : value(_value) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
+    // Conversion to SIMD register
+    simdjson_inline operator const __m512i&() const { return this->value; }
+    simdjson_inline operator __m512i&() { return this->value; }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return _mm512_or_si512(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return _mm512_and_si512(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return _mm512_xor_si512(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return _mm512_andnot_si512(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
+  // Forward-declared so they can be used by splat and friends.
+  template<typename T>
+  struct simd8;
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    typedef uint32_t bitmask_t;
+    typedef uint64_t bitmask2_t;
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m512i _value) : base<simd8<T>>(_value) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+    friend simdjson_really_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) {
+      return _mm512_cmpeq_epi8_mask(lhs, rhs);
+    }
 
-  json.remove_utf8_bom();
+    static const int SIZE = sizeof(base<T>::value);
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+     // workaround for compilers unable to figure out that 16 - N is a constant (GCC 8)
+      constexpr int shift = 16 - N;
+      return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), shift);
+    }
+  };
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
+    simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) { return _mm512_set1_epi8(_value); }
+    static simdjson_inline simd8<T> zero() { return _mm512_setzero_si512(); }
+    static simdjson_inline simd8<T> load(const T values[64]) {
+      return _mm512_loadu_si512(reinterpret_cast<const __m512i *>(values));
+    }
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m512i _value) : base8<T>(_value) {}
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
+    // Store to array
+    simdjson_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<__m512i *>(dst), *this); }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm512_add_epi8(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm512_sub_epi8(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
 
-namespace simdjson {
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return _mm512_shuffle_epi8(lookup_table, *this);
+    }
 
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(haswell::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(std::forward<haswell::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::parser>(error) {}
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
+    // get written.
+    // Design consideration: it seems like a function with the
+    // signature simd8<L> compress(uint32_t mask) would be
+    // sensible, but the AVX ISA makes this kind of approach difficult.
+    template<typename L>
+    simdjson_inline void compress(uint64_t mask, L * output) const {
+      _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
+    }
 
-} // namespace simdjson
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
+    }
+  };
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for haswell */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for haswell: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m512i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t values[64]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15,
+      int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
+      int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31,
+      int8_t v32, int8_t v33, int8_t v34, int8_t v35, int8_t v36, int8_t v37, int8_t v38, int8_t v39,
+      int8_t v40, int8_t v41, int8_t v42, int8_t v43, int8_t v44, int8_t v45, int8_t v46, int8_t v47,
+      int8_t v48, int8_t v49, int8_t v50, int8_t v51, int8_t v52, int8_t v53, int8_t v54, int8_t v55,
+      int8_t v56, int8_t v57, int8_t v58, int8_t v59, int8_t v60, int8_t v61, int8_t v62, int8_t v63
+    ) : simd8(_mm512_set_epi8(
+      v63, v62, v61, v60, v59, v58, v57, v56,
+      v55, v54, v53, v52, v51, v50, v49, v48,
+      v47, v46, v45, v44, v43, v42, v41, v40,
+      v39, v38, v37, v36, v35, v34, v33, v32,
+      v31, v30, v29, v28, v27, v26, v25, v24,
+      v23, v22, v21, v20, v19, v18, v17, v16,
+      v15, v14, v13, v12, v11, v10,  v9,  v8,
+       v7,  v6,  v5,  v4,  v3,  v2,  v1,  v0
+    )) {}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-namespace simdjson {
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm512_max_epi8(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm512_min_epi8(*this, other); }
 
-namespace haswell {
-namespace ondemand {
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(*this, other),_mm512_set1_epi8(uint8_t(0x80))); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(other, *this),_mm512_set1_epi8(uint8_t(0x80))); }
+  };
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m512i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t values[64]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15,
+      uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
+      uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31,
+      uint8_t v32, uint8_t v33, uint8_t v34, uint8_t v35, uint8_t v36, uint8_t v37, uint8_t v38, uint8_t v39,
+      uint8_t v40, uint8_t v41, uint8_t v42, uint8_t v43, uint8_t v44, uint8_t v45, uint8_t v46, uint8_t v47,
+      uint8_t v48, uint8_t v49, uint8_t v50, uint8_t v51, uint8_t v52, uint8_t v53, uint8_t v54, uint8_t v55,
+      uint8_t v56, uint8_t v57, uint8_t v58, uint8_t v59, uint8_t v60, uint8_t v61, uint8_t v62, uint8_t v63
+    ) : simd8(_mm512_set_epi8(
+      v63, v62, v61, v60, v59, v58, v57, v56,
+      v55, v54, v53, v52, v51, v50, v49, v48,
+      v47, v46, v45, v44, v43, v42, v41, v40,
+      v39, v38, v37, v36, v35, v34, v33, v32,
+      v31, v30, v29, v28, v27, v26, v25, v24,
+      v23, v22, v21, v20, v19, v18, v17, v16,
+      v15, v14, v13, v12, v11, v10,  v9,  v8,
+       v7,  v6,  v5,  v4,  v3,  v2,  v1,  v0
+    )) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
-}
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm512_adds_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm512_subs_epu8(*this, other); }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
-}
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm512_max_epu8(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm512_min_epu8(other, *this); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline uint64_t operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline uint64_t operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return _mm512_mask_blend_epi8(*this == uint8_t(0), _mm512_set1_epi8(0), _mm512_set1_epi8(-1)); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+
+    simdjson_inline bool is_ascii() const { return _mm512_movepi8_mask(*this) == 0; }
+    simdjson_inline bool bits_not_set_anywhere() const {
+      return !_mm512_test_epi8_mask(*this, *this);
     }
-  }
-  return SUCCESS;
-}
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return !_mm512_test_epi8_mask(*this, bits); }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm512_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm512_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
+    // Get one of the bits and make a bitmask out of it.
+    // e.g. value.get_bit<7>() gets the high bit
+    template<int N>
+    simdjson_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
-}
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
-}
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
+    simdjson_inline simd8x64(const simd8<T> chunk0) : chunks{chunk0} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr)} {}
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
-}
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      this->chunks[0].compress(mask, output);
+      return 64 - count_ones(mask);
+    }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+    }
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
+    simdjson_inline simd8<T> reduce_or() const {
+      return this->chunks[0];
+    }
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
+    simdjson_inline simd8x64<T> bit_or(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return simd8x64<T>(
+        this->chunks[0] | mask
+      );
     }
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return this->chunks[0] == mask;
+    }
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return this->chunks[0] == other.chunks[0];
+    }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return this->chunks[0] <= mask;
+    }
+  }; // struct simd8x64<T>
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+} // namespace simd
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+} // unnamed namespace
+} // namespace icelake
+} // namespace simdjson
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+#endif // SIMDJSON_ICELAKE_SIMD_H
+/* end file simdjson/icelake/simd.h */
+/* including simdjson/icelake/stringparsing_defs.h: #include "simdjson/icelake/stringparsing_defs.h" */
+/* begin file simdjson/icelake/stringparsing_defs.h */
+#ifndef SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
+#define SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/simd.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+namespace simdjson {
+namespace icelake {
+namespace {
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
+using namespace simd;
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
-
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
-
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
+public:
+  static constexpr uint32_t BYTES_PROCESSED = 64;
+  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
+  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
+  simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
+  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
+  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+  uint64_t bs_bits;
+  uint64_t quote_bits;
+}; // struct backslash_and_quote
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
+simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 15 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v(src);
+  // store to dest unconditionally - we can overwrite the bits we don't like later
+  v.store(dst);
+  return {
+      static_cast<uint64_t>(v == '\\'), // bs_bits
+      static_cast<uint64_t>(v == '"'), // quote_bits
+  };
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
+} // unnamed namespace
+} // namespace icelake
+} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
+#endif // SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
+/* end file simdjson/icelake/stringparsing_defs.h */
+/* including simdjson/icelake/numberparsing_defs.h: #include "simdjson/icelake/numberparsing_defs.h" */
+/* begin file simdjson/icelake/numberparsing_defs.h */
+#ifndef SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
+#define SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
 
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
-}
+namespace simdjson {
+namespace icelake {
+namespace numberparsing {
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  // this actually computes *16* values so we are being wasteful.
+  const __m128i ascii0 = _mm_set1_epi8('0');
+  const __m128i mul_1_10 =
+      _mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
+  const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
+  const __m128i mul_1_10000 =
+      _mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
+  const __m128i input = _mm_sub_epi8(
+      _mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
+  const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
+  const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
+  const __m128i t3 = _mm_packus_epi32(t2, t2);
+  const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
+  return _mm_cvtsi128_si32(
+      t4); // only captures the sum of the first 8 digits, drop the rest
 }
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
+/** @private */
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+#if SIMDJSON_IS_ARM64
+  // ARM64 has native support for 64-bit multiplications, no need to emultate
+  answer.high = __umulh(value1, value2);
+  answer.low = value1 * value2;
+#else
+  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
+#endif // SIMDJSON_IS_ARM64
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
+#endif
   return answer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
+} // namespace numberparsing
+} // namespace icelake
+} // namespace simdjson
+
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
+
+#endif // SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
+/* end file simdjson/icelake/numberparsing_defs.h */
+/* end file simdjson/icelake/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for icelake: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for icelake */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
 #endif
-  return true;
-}
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
-    }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for icelake: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+/**
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
+ */
+namespace ondemand {
+
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
+
+/** @copydoc simdjson::icelake::number_type */
+using number_type = simdjson::icelake::number_type;
+
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
+
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for icelake */
+/* including simdjson/generic/ondemand/deserialize.h for icelake: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for icelake */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <concepts>
+namespace simdjson {
+
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
     }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
   }
-  return SUCCESS;
-}
+};
+} // namespace tag_invoke_fn_ns
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
 
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
-}
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
 
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<icelake::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = icelake::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = icelake::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = icelake::ondemand::value;
+  using document_type = icelake::ondemand::document;
+  using document_reference_type = icelake::ondemand::document_reference;
+
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
   }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
 
-simdjson_inline simdjson_result<haswell::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
   }
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
   }
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
-  }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
-  }
-  return result;
-}
+} deserialize{};
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
+} // namespace simdjson
 
-  return _json_iter->skip_child(depth());
-}
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
 
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
-}
+/* end file simdjson/generic/ondemand/deserialize.h for icelake */
+/* including simdjson/generic/ondemand/value_iterator.h for icelake: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
-}
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
-}
+/**
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
+ *
+ * @private This is not intended for external use.
+ */
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
+  /**
+   * The starting token index for this value
+   */
+  token_position _start_position{};
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
-}
+public:
+  simdjson_inline value_iterator() noexcept = default;
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
-}
+  /**
+   * Denote that we're starting a document.
+   */
+  simdjson_inline void start_document() noexcept;
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
-}
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
-}
+  /**
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   *
+   * Optimized for scalars.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
+  /**
+   * Tell whether the iterator is at the start of the value
+   */
+  simdjson_inline bool at_start() const noexcept;
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
-}
+  /**
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   */
+  simdjson_inline bool is_open() const noexcept;
 
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
+  /**
+   * Tell whether the value is at an object's first field (just after the {).
+   */
+  simdjson_inline bool at_first_field() const noexcept;
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+  /**
+   * Abandon all iteration.
+   */
+  simdjson_inline void abandon() noexcept;
 
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
-  }
+  /**
+   * Get the child value as a value_iterator.
+   */
+  simdjson_inline value_iterator child_value() const noexcept;
 
+  /**
+   * Get the depth of this value.
+   */
+  simdjson_inline int32_t depth() const noexcept;
 
-  return SUCCESS;
-}
+  /**
+   * Get the JSON type of this value.
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
 
+  /**
+   * @addtogroup object Object iteration
+   *
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
+   *
+   * @{
+   */
 
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+  /**
+   * Start an object iteration.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  /**
+   * Start an object iteration from the root.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  /**
+   * Checks whether an object could be started from the root. May be called by start_root_object.
+   *
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  /**
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  /**
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+  /**
+   * Moves to the next field in an object.
+   *
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
 
-  assert_at_non_root_start();
-  return _json_iter->peek();
-}
+  /**
+   * Get the current field's key.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
 
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
+  /**
+   * Pass the : in the field and move to its value.
+   */
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
 
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
+  /**
+   * Find the next field with the given key.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
 
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+  /**
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
 
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
-}
+  /**
+   * Find the field with the given key without regard to order, and *without* unescaping.
+   *
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
 
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
-}
-
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
-}
-
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
-}
-
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+  /** @} */
 
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
-}
+  /**
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
+   */
 
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
-}
+  /**
+   * Check for an opening [ and start an array iteration.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  /**
+   * Check for an opening [ and start an array iteration while at the root.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  /**
+   * Checks whether an array could be started from the root. May be called by start_root_array.
+   *
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  /**
+   * Start an array iteration, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  /**
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
-}
+  /**
+   * Moves to the next element in an array.
+   *
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
-}
+  /**
+   * Get a child value iterator.
+   */
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
 
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+  /** @} */
 
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+  /**
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
+   */
 
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
 
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
 
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
-  }
-}
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
-}
+  /** @} */
+protected:
+  /**
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  /**
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  /**
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
-}
+  /**
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
+   *
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
 
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
 
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
+   *
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   */
 
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
-}
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
 
-} // namespace ondemand
-} // namespace haswell
-} // namespace simdjson
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
 
-namespace simdjson {
 
-simdjson_inline simdjson_result<haswell::ondemand::value_iterator>::simdjson_result(haswell::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::value_iterator>(std::forward<haswell::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<haswell::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<haswell::ondemand::value_iterator>(error) {}
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
 
-} // namespace simdjson
+  /**
+   * Advance to a place expecting a value (increasing depth).
+   *
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
+   */
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for haswell */
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
 
+  simdjson_inline bool is_at_start() const noexcept;
+  /**
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
+   *
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   */
+  simdjson_inline bool is_at_iterator_start() const noexcept;
 
-/* end file simdjson/generic/ondemand/amalgamated.h for haswell */
-/* including simdjson/haswell/end.h: #include "simdjson/haswell/end.h" */
-/* begin file simdjson/haswell/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/haswell/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
+   *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
+   */
+  simdjson_inline bool is_at_key() const noexcept;
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
-SIMDJSON_UNTARGET_REGION
-#endif
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-/* undefining SIMDJSON_IMPLEMENTATION from "haswell" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/haswell/end.h */
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
 
-#endif // SIMDJSON_HASWELL_ONDEMAND_H
-/* end file simdjson/haswell/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
-/* including simdjson/icelake/ondemand.h: #include "simdjson/icelake/ondemand.h" */
-/* begin file simdjson/icelake/ondemand.h */
-#ifndef SIMDJSON_ICELAKE_ONDEMAND_H
-#define SIMDJSON_ICELAKE_ONDEMAND_H
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
-/* including simdjson/icelake/begin.h: #include "simdjson/icelake/begin.h" */
-/* begin file simdjson/icelake/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "icelake" */
-#define SIMDJSON_IMPLEMENTATION icelake
-/* including simdjson/icelake/base.h: #include "simdjson/icelake/base.h" */
-/* begin file simdjson/icelake/base.h */
-#ifndef SIMDJSON_ICELAKE_BASE_H
-#define SIMDJSON_ICELAKE_BASE_H
+  friend class document;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
 
-// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_ICELAKE
 namespace simdjson {
-/**
- * Implementation for Icelake (Intel AVX512).
- */
-namespace icelake {
 
-class implementation;
+template<>
+struct simdjson_result<icelake::ondemand::value_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::value_iterator> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
 
-} // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_ICELAKE_BASE_H
-/* end file simdjson/icelake/base.h */
-/* including simdjson/icelake/intrinsics.h: #include "simdjson/icelake/intrinsics.h" */
-/* begin file simdjson/icelake/intrinsics.h */
-#ifndef SIMDJSON_ICELAKE_INTRINSICS_H
-#define SIMDJSON_ICELAKE_INTRINSICS_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for icelake */
+/* including simdjson/generic/ondemand/value.h for icelake: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#if SIMDJSON_VISUAL_STUDIO
-// under clang within visual studio, this will include <x86intrin.h>
-#include <intrin.h>  // visual studio or clang
-#else
-#include <x86intrin.h> // elsewhere
-#endif // SIMDJSON_VISUAL_STUDIO
+#include <type_traits>
 
-#if SIMDJSON_CLANG_VISUAL_STUDIO
+namespace simdjson {
+
+namespace icelake {
+namespace ondemand {
 /**
- * You are not supposed, normally, to include these
- * headers directly. Instead you should either include intrin.h
- * or x86intrin.h. However, when compiling with clang
- * under Windows (i.e., when _MSC_VER is set), these headers
- * only get included *if* the corresponding features are detected
- * from macros:
- * e.g., if __AVX2__ is set... in turn,  we normally set these
- * macros by compiling against the corresponding architecture
- * (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole
- * software with these advanced instructions. In simdjson, we
- * want to compile the whole program for a generic target,
- * and only target our specific kernels. As a workaround,
- * we directly include the needed headers. These headers would
- * normally guard against such usage, but we carefully included
- * <x86intrin.h>  (or <intrin.h>) before, so the headers
- * are fooled.
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
  */
-#include <bmiintrin.h>   // for _blsr_u64
-#include <lzcntintrin.h> // for  __lzcnt64
-#include <immintrin.h>   // for most things (AVX2, AVX512, _popcnt64)
-#include <smmintrin.h>
-#include <tmmintrin.h>
-#include <avxintrin.h>
-#include <avx2intrin.h>
-#include <wmmintrin.h>   // for  _mm_clmulepi64_si128
-// Important: we need the AVX-512 headers:
-#include <avx512fintrin.h>
-#include <avx512dqintrin.h>
-#include <avx512cdintrin.h>
-#include <avx512bwintrin.h>
-#include <avx512vlintrin.h>
-#include <avx512vbmiintrin.h>
-#include <avx512vbmi2intrin.h>
-// unfortunately, we may not get _blsr_u64, but, thankfully, clang
-// has it as a macro.
-#ifndef _blsr_u64
-// we roll our own
-#define _blsr_u64(n) ((n - 1) & n)
-#endif //  _blsr_u64
-#endif // SIMDJSON_CLANG_VISUAL_STUDIO
-
-static_assert(sizeof(__m512i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for icelake");
-
-#endif // SIMDJSON_ICELAKE_INTRINSICS_H
-/* end file simdjson/icelake/intrinsics.h */
+class value {
+public:
+  /**
+   * Create a new invalid value.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline value() noexcept = default;
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
-SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt,popcnt")
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
 #endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
 
-/* including simdjson/icelake/bitmanipulation.h: #include "simdjson/icelake/bitmanipulation.h" */
-/* begin file simdjson/icelake/bitmanipulation.h */
-#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
-#define SIMDJSON_ICELAKE_BITMANIPULATION_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace {
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  return (int)_tzcnt_u64(input_num);
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO
-  ////////
-  // You might expect the next line to be equivalent to
-  // return (int)_tzcnt_u64(input_num);
-  // but the generated code differs and might be less efficient?
-  ////////
-  return __builtin_ctzll(input_num);
-#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
-}
-
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return _blsr_u64(input_num);
-}
-
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-  return int(_lzcnt_u64(input_num));
-}
-
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
-  // note: we do not support legacy 32-bit Windows
-  return __popcnt64(input_num);// Visual Studio wants two underscores
-}
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
 #else
-simdjson_inline long long int count_ones(uint64_t input_num) {
-  return _popcnt64(input_num);
-}
+    noexcept
 #endif
-
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
-                                uint64_t *result) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  return _addcarry_u64(0, value1, value2,
-                       reinterpret_cast<unsigned __int64 *>(result));
-#else
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
 #endif
-}
-
-} // unnamed namespace
-} // namespace icelake
-} // namespace simdjson
-
-#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
-/* end file simdjson/icelake/bitmanipulation.h */
-/* including simdjson/icelake/bitmask.h: #include "simdjson/icelake/bitmask.h" */
-/* begin file simdjson/icelake/bitmask.h */
-#ifndef SIMDJSON_ICELAKE_BITMASK_H
-#define SIMDJSON_ICELAKE_BITMASK_H
+  }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
-namespace simdjson {
-namespace icelake {
-namespace {
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
-  // There should be no such thing with a processor supporting avx2
-  // but not clmul.
-  __m128i all_ones = _mm_set1_epi8('\xFF');
-  __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
-  return _mm_cvtsi128_si64(result);
-}
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
-} // unnamed namespace
-} // namespace icelake
-} // namespace simdjson
+  /**
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
-#endif // SIMDJSON_ICELAKE_BITMASK_H
-/* end file simdjson/icelake/bitmask.h */
-/* including simdjson/icelake/simd.h: #include "simdjson/icelake/simd.h" */
-/* begin file simdjson/icelake/simd.h */
-#ifndef SIMDJSON_ICELAKE_SIMD_H
-#define SIMDJSON_ICELAKE_SIMD_H
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
-#if defined(__GNUC__) && !defined(__clang__)
-#if __GNUC__ == 8
-#define SIMDJSON_GCC8 1
-#endif //  __GNUC__ == 8
-#endif // defined(__GNUC__) && !defined(__clang__)
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
-#if SIMDJSON_GCC8
-/**
- * GCC 8 fails to provide _mm512_set_epi8. We roll our own.
- */
-inline __m512i _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8, uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12, uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16, uint8_t a17, uint8_t a18, uint8_t a19, uint8_t a20, uint8_t a21, uint8_t a22, uint8_t a23, uint8_t a24, uint8_t a25, uint8_t a26, uint8_t a27, uint8_t a28, uint8_t a29, uint8_t a30, uint8_t a31, uint8_t a32, uint8_t a33, uint8_t a34, uint8_t a35, uint8_t a36, uint8_t a37, uint8_t a38, uint8_t a39, uint8_t a40, uint8_t a41, uint8_t a42, uint8_t a43, uint8_t a44, uint8_t a45, uint8_t a46, uint8_t a47, uint8_t a48, uint8_t a49, uint8_t a50, uint8_t a51, uint8_t a52, uint8_t a53, uint8_t a54, uint8_t a55, uint8_t a56, uint8_t a57, uint8_t a58, uint8_t a59, uint8_t a60, uint8_t a61, uint8_t a62, uint8_t a63) {
-  return _mm512_set_epi64(uint64_t(a7) + (uint64_t(a6) << 8) + (uint64_t(a5) << 16) + (uint64_t(a4) << 24) + (uint64_t(a3) << 32) + (uint64_t(a2) << 40) + (uint64_t(a1) << 48) + (uint64_t(a0) << 56),
-                          uint64_t(a15) + (uint64_t(a14) << 8) + (uint64_t(a13) << 16) + (uint64_t(a12) << 24) + (uint64_t(a11) << 32) + (uint64_t(a10) << 40) + (uint64_t(a9) << 48) + (uint64_t(a8) << 56),
-                          uint64_t(a23) + (uint64_t(a22) << 8) + (uint64_t(a21) << 16) + (uint64_t(a20) << 24) + (uint64_t(a19) << 32) + (uint64_t(a18) << 40) + (uint64_t(a17) << 48) + (uint64_t(a16) << 56),
-                          uint64_t(a31) + (uint64_t(a30) << 8) + (uint64_t(a29) << 16) + (uint64_t(a28) << 24) + (uint64_t(a27) << 32) + (uint64_t(a26) << 40) + (uint64_t(a25) << 48) + (uint64_t(a24) << 56),
-                          uint64_t(a39) + (uint64_t(a38) << 8) + (uint64_t(a37) << 16) + (uint64_t(a36) << 24) + (uint64_t(a35) << 32) + (uint64_t(a34) << 40) + (uint64_t(a33) << 48) + (uint64_t(a32) << 56),
-                          uint64_t(a47) + (uint64_t(a46) << 8) + (uint64_t(a45) << 16) + (uint64_t(a44) << 24) + (uint64_t(a43) << 32) + (uint64_t(a42) << 40) + (uint64_t(a41) << 48) + (uint64_t(a40) << 56),
-                          uint64_t(a55) + (uint64_t(a54) << 8) + (uint64_t(a53) << 16) + (uint64_t(a52) << 24) + (uint64_t(a51) << 32) + (uint64_t(a50) << 40) + (uint64_t(a49) << 48) + (uint64_t(a48) << 56),
-                          uint64_t(a63) + (uint64_t(a62) << 8) + (uint64_t(a61) << 16) + (uint64_t(a60) << 24) + (uint64_t(a59) << 32) + (uint64_t(a58) << 40) + (uint64_t(a57) << 48) + (uint64_t(a56) << 56));
-}
-#endif // SIMDJSON_GCC8
+  /**
+   * Cast this JSON value (inside string) to a double
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
 
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Equivalent to get<std::string_view>().
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
+   *
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
 
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   */
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
 
-namespace simdjson {
-namespace icelake {
-namespace {
-namespace simd {
+  /**
+   * Cast this JSON value to a "wobbly" string.
+   *
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename Child>
-  struct base {
-    __m512i value;
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
 
-    // Zero constructor
-    simdjson_inline base() : value{__m512i()} {}
+  /**
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
+   *
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-    // Conversion from SIMD register
-    simdjson_inline base(const __m512i _value) : value(_value) {}
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
+   *
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  /**
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() noexcept(false);
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Equivalent to get<std::string_view>().
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
+#endif
 
-    // Conversion to SIMD register
-    simdjson_inline operator const __m512i&() const { return this->value; }
-    simdjson_inline operator __m512i&() { return this->value; }
+  /**
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   *
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
 
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return _mm512_or_si512(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return _mm512_and_si512(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return _mm512_xor_si512(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return _mm512_andnot_si512(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename T>
-  struct simd8;
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    typedef uint32_t bitmask_t;
-    typedef uint64_t bitmask2_t;
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m512i _value) : base<simd8<T>>(_value) {}
-
-    friend simdjson_really_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) {
-      return _mm512_cmpeq_epi8_mask(lhs, rhs);
-    }
-
-    static const int SIZE = sizeof(base<T>::value);
+  /**
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  /**
+   * Checks whether the value is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-     // workaround for compilers unable to figure out that 16 - N is a constant (GCC 8)
-      constexpr int shift = 16 - N;
-      return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), shift);
-    }
-  };
+  /**
+   * Checks whether the value is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
-    simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
+   */
+  simdjson_inline std::string_view raw_json_token() noexcept;
 
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) { return _mm512_set1_epi8(_value); }
-    static simdjson_inline simd8<T> zero() { return _mm512_setzero_si512(); }
-    static simdjson_inline simd8<T> load(const T values[64]) {
-      return _mm512_loadu_si512(reinterpret_cast<const __m512i *>(values));
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  /**
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m512i _value) : base8<T>(_value) {}
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
 
-    // Store to array
-    simdjson_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<__m512i *>(dst), *this); }
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
 
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm512_add_epi8(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return _mm512_sub_epi8(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
 
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return _mm512_shuffle_epi8(lookup_table, *this);
-    }
 
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
-    // get written.
-    // Design consideration: it seems like a function with the
-    // signature simd8<L> compress(uint32_t mask) would be
-    // sensible, but the AVX ISA makes this kind of approach difficult.
-    template<typename L>
-    simdjson_inline void compress(uint64_t mask, L * output) const {
-      _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
-    }
+protected:
+  /**
+   * Create a value.
+   */
+  simdjson_inline value(const value_iterator &iter) noexcept;
 
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
-    }
-  };
+  /**
+   * Skip this value, allowing iteration to continue.
+   */
+  simdjson_inline void skip() noexcept;
 
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m512i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t values[64]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15,
-      int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
-      int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31,
-      int8_t v32, int8_t v33, int8_t v34, int8_t v35, int8_t v36, int8_t v37, int8_t v38, int8_t v39,
-      int8_t v40, int8_t v41, int8_t v42, int8_t v43, int8_t v44, int8_t v45, int8_t v46, int8_t v47,
-      int8_t v48, int8_t v49, int8_t v50, int8_t v51, int8_t v52, int8_t v53, int8_t v54, int8_t v55,
-      int8_t v56, int8_t v57, int8_t v58, int8_t v59, int8_t v60, int8_t v61, int8_t v62, int8_t v63
-    ) : simd8(_mm512_set_epi8(
-      v63, v62, v61, v60, v59, v58, v57, v56,
-      v55, v54, v53, v52, v51, v50, v49, v48,
-      v47, v46, v45, v44, v43, v42, v41, v40,
-      v39, v38, v37, v36, v35, v34, v33, v32,
-      v31, v30, v29, v28, v27, v26, v25, v24,
-      v23, v22, v21, v20, v19, v18, v17, v16,
-      v15, v14, v13, v12, v11, v10,  v9,  v8,
-       v7,  v6,  v5,  v4,  v3,  v2,  v1,  v0
-    )) {}
+  /**
+   * Start a value at the current position.
+   *
+   * (It should already be started; this is just a self-documentation method.)
+   */
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
 
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  /**
+   * Resume a value.
+   */
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
 
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm512_max_epi8(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm512_min_epi8(*this, other); }
+  /**
+   * Get the object, starting or resuming it as necessary
+   */
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
 
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(*this, other),_mm512_set1_epi8(uint8_t(0x80))); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(other, *this),_mm512_set1_epi8(uint8_t(0x80))); }
-  };
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
 
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m512i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t values[64]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15,
-      uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
-      uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31,
-      uint8_t v32, uint8_t v33, uint8_t v34, uint8_t v35, uint8_t v36, uint8_t v37, uint8_t v38, uint8_t v39,
-      uint8_t v40, uint8_t v41, uint8_t v42, uint8_t v43, uint8_t v44, uint8_t v45, uint8_t v46, uint8_t v47,
-      uint8_t v48, uint8_t v49, uint8_t v50, uint8_t v51, uint8_t v52, uint8_t v53, uint8_t v54, uint8_t v55,
-      uint8_t v56, uint8_t v57, uint8_t v58, uint8_t v59, uint8_t v60, uint8_t v61, uint8_t v62, uint8_t v63
-    ) : simd8(_mm512_set_epi8(
-      v63, v62, v61, v60, v59, v58, v57, v56,
-      v55, v54, v53, v52, v51, v50, v49, v48,
-      v47, v46, v45, v44, v43, v42, v41, v40,
-      v39, v38, v37, v36, v35, v34, v33, v32,
-      v31, v30, v29, v28, v27, v26, v25, v24,
-      v23, v22, v21, v20, v19, v18, v17, v16,
-      v15, v14, v13, v12, v11, v10,  v9,  v8,
-       v7,  v6,  v5,  v4,  v3,  v2,  v1,  v0
-    )) {}
+  value_iterator iter{};
 
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  friend class document;
+  friend class array_iterator;
+  friend class field;
+  friend class object;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
+  friend class field;
+};
 
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm512_adds_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm512_subs_epu8(*this, other); }
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
 
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm512_max_epu8(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm512_min_epu8(other, *this); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline uint64_t operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline uint64_t operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
+namespace simdjson {
 
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return _mm512_mask_blend_epi8(*this == uint8_t(0), _mm512_set1_epi8(0), _mm512_set1_epi8(-1)); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+template<>
+struct simdjson_result<icelake::ondemand::value> : public icelake::implementation_simdjson_result_base<icelake::ondemand::value> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-    simdjson_inline bool is_ascii() const { return _mm512_movepi8_mask(*this) == 0; }
-    simdjson_inline bool bits_not_set_anywhere() const {
-      return !_mm512_test_epi8_mask(*this, *this);
-    }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return !_mm512_test_epi8_mask(*this, bits); }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm512_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm512_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
-    // Get one of the bits and make a bitmask out of it.
-    // e.g. value.get_bit<7>() gets the high bit
-    template<int N>
-    simdjson_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); }
-  };
+  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() noexcept;
 
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
 
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
-    simdjson_inline simd8x64(const simd8<T> chunk0) : chunks{chunk0} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr)} {}
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
 
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      this->chunks[0].compress(mask, output);
-      return 64 - count_ones(mask);
-    }
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator icelake::ondemand::array() noexcept(false);
+  simdjson_inline operator icelake::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
 
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-    }
-
-    simdjson_inline simd8<T> reduce_or() const {
-      return this->chunks[0];
-    }
-
-    simdjson_inline simd8x64<T> bit_or(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return simd8x64<T>(
-        this->chunks[0] | mask
-      );
-    }
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) noexcept;
 
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return this->chunks[0] == mask;
-    }
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) noexcept = delete;
 
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return this->chunks[0] == other.chunks[0];
-    }
+  /**
+   * Get the type of this JSON value.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   */
+  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
 
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return this->chunks[0] <= mask;
-    }
-  }; // struct simd8x64<T>
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-} // namespace simd
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
 
-} // unnamed namespace
-} // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_ICELAKE_SIMD_H
-/* end file simdjson/icelake/simd.h */
-/* including simdjson/icelake/stringparsing_defs.h: #include "simdjson/icelake/stringparsing_defs.h" */
-/* begin file simdjson/icelake/stringparsing_defs.h */
-#ifndef SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
-#define SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for icelake */
+/* including simdjson/generic/ondemand/logger.h for icelake: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/simd.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
-namespace {
-
-using namespace simd;
-
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 64;
-  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
-
-  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
-  simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
-  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
-  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
-
-  uint64_t bs_bits;
-  uint64_t quote_bits;
-}; // struct backslash_and_quote
-
-simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 15 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v(src);
-  // store to dest unconditionally - we can overwrite the bits we don't like later
-  v.store(dst);
-  return {
-      static_cast<uint64_t>(v == '\\'), // bs_bits
-      static_cast<uint64_t>(v == '"'), // quote_bits
-  };
-}
-
-} // unnamed namespace
-} // namespace icelake
-} // namespace simdjson
-
-#endif // SIMDJSON_ICELAKE_STRINGPARSING_DEFS_H
-/* end file simdjson/icelake/stringparsing_defs.h */
-/* including simdjson/icelake/numberparsing_defs.h: #include "simdjson/icelake/numberparsing_defs.h" */
-/* begin file simdjson/icelake/numberparsing_defs.h */
-#ifndef SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
-#define SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+namespace ondemand {
 
-namespace simdjson {
-namespace icelake {
-namespace numberparsing {
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
 
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  // this actually computes *16* values so we are being wasteful.
-  const __m128i ascii0 = _mm_set1_epi8('0');
-  const __m128i mul_1_10 =
-      _mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
-  const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
-  const __m128i mul_1_10000 =
-      _mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
-  const __m128i input = _mm_sub_epi8(
-      _mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
-  const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
-  const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
-  const __m128i t3 = _mm_packus_epi32(t2, t2);
-  const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
-  return _mm_cvtsi128_si32(
-      t4); // only captures the sum of the first 8 digits, drop the rest
-}
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
+};
 
-/** @private */
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-#if SIMDJSON_IS_ARM64
-  // ARM64 has native support for 64-bit multiplications, no need to emultate
-  answer.high = __umulh(value1, value2);
-  answer.low = value1 * value2;
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
 #else
-  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
-#endif // SIMDJSON_IS_ARM64
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
-#endif
-  return answer;
-}
-
-} // namespace numberparsing
-} // namespace icelake
-} // namespace simdjson
-
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-
-#endif // SIMDJSON_ICELAKE_NUMBERPARSING_DEFS_H
-/* end file simdjson/icelake/numberparsing_defs.h */
-/* end file simdjson/icelake/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for icelake: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for icelake */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
+  static constexpr const bool LOG_ENABLED = false;
 #endif
 
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for icelake: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
-
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
-
-/** @copydoc simdjson::icelake::number_type */
-using number_type = simdjson::icelake::number_type;
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
 
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
 
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
 
+} // namespace logger
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for icelake */
-/* including simdjson/generic/ondemand/deserialize.h for icelake: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for icelake */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-namespace simdjson {
-
-namespace tag_invoke_fn_ns {
-void tag_invoke();
-
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
-
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
-
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
-
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
-
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
-
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
-
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
-
-
-struct deserialize_tag;
-
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<icelake::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<icelake::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<icelake::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<icelake::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
-
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
-
-template <typename T, typename ValT = icelake::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
-
-template <typename T, typename ValT = icelake::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-template <typename T, typename ValT = icelake::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
-
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = icelake::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = icelake::ondemand::value;
-  using document_type = icelake::ondemand::document;
-  using document_reference_type = icelake::ondemand::document_reference;
-
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-
-} deserialize{};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for icelake */
-/* including simdjson/generic/ondemand/value_iterator.h for icelake: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for icelake */
+/* including simdjson/generic/ondemand/token_iterator.h for icelake: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -68090,467 +67321,472 @@ namespace icelake {
 namespace ondemand {
 
 /**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
  *
  * @private This is not intended for external use.
  */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
-
+class token_iterator {
 public:
-  simdjson_inline value_iterator() noexcept = default;
-
-  /**
-   * Denote that we're starting a document.
-   */
-  simdjson_inline void start_document() noexcept;
-
   /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   * Create a new invalid token_iterator.
    *
-   * Optimized for scalars.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
 
   /**
-   * Tell whether the iterator is at the EOF mark
+   * Advance to the next token (returning the current one).
    */
-  simdjson_inline bool at_end() const noexcept;
-
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
   /**
-   * Tell whether the iterator is at the start of the value
+   * Reports the current offset in bytes from the start of the underlying buffer.
    */
-  simdjson_inline bool at_start() const noexcept;
-
+  simdjson_inline uint32_t current_offset() const noexcept;
   /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   * Get the JSON text for a given token (relative).
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
    */
-  simdjson_inline bool is_open() const noexcept;
-
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Tell whether the value is at an object's first field (just after the {).
+   * Get the maximum length of the JSON text for a given token.
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline bool at_first_field() const noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
 
   /**
-   * Abandon all iteration.
+   * Get the JSON text for a given token.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
+   *
    */
-  simdjson_inline void abandon() noexcept;
-
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Get the child value as a value_iterator.
-   */
-  simdjson_inline value_iterator child_value() const noexcept;
-
+   * Get the maximum length of the JSON text for a given token.
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token.
+   */
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Get the depth of this value.
+   * Get the maximum length of the JSON text for a root token.
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token (start of the document).
    */
-  simdjson_inline int32_t depth() const noexcept;
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Return the current index.
+   */
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Reset to a previously saved index.
+   */
+  simdjson_inline void set_position(token_position target_position) noexcept;
+
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
+
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+
+protected:
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
 
   /**
-   * Get the JSON type of this value.
+   * Get the index of the JSON text for a given token (relative).
    *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
-
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
   /**
-   * @addtogroup object Object iteration
+   * Get the index of the JSON text for a given token.
    *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
    *
-   * @{
    */
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+
+  const uint8_t *buf{};
+  token_position _position{};
+
+  friend class json_iterator;
+  friend class value_iterator;
+  friend class object;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+};
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<icelake::ondemand::token_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::token_iterator> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for icelake */
+/* including simdjson/generic/ondemand/json_iterator.h for icelake: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
+ */
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
   /**
-   * Start an object iteration.
+   * Next free location in the string buffer.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  uint8_t *_string_buf_loc{};
   /**
-   * Start an object iteration from the root.
+   * JSON error, if there is one.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
+   *
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  error_code error{SUCCESS};
   /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
+   * Depth of the current token in the JSON.
    *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
    */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  depth_t _depth{};
   /**
-   * Start an object iteration after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  token_position _root{};
   /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
+  bool _streaming{false};
 
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
-   * Moves to the next field in an object.
-   *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   * Skips a JSON value, whether it is a scalar, array or object.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
   /**
-   * Get the current field's key.
+   * Tell whether the iterator is still at the start
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
+  simdjson_inline bool at_root() const noexcept;
 
   /**
-   * Pass the : in the field and move to its value.
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
    */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
+  simdjson_inline bool streaming() const noexcept;
 
   /**
-   * Find the next field with the given key.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * Get the root value iterator
    */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
+  simdjson_inline token_position root_position() const noexcept;
+  /**
+   * Assert that we are at the document depth (== 1)
+   */
+  simdjson_inline void assert_at_document_depth() const noexcept;
+  /**
+   * Assert that we are at the root of the document
+   */
+  simdjson_inline void assert_at_root() const noexcept;
 
   /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * Tell whether the iterator is at the EOF mark
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
+  simdjson_inline bool at_end() const noexcept;
 
   /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
-   *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * Tell whether the iterator is live (has not been moved).
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
+  simdjson_inline bool is_alive() const noexcept;
 
-  /** @} */
+  /**
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   */
+  simdjson_inline void abandon() noexcept;
 
   /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
+   * Advance the current token without modifying depth.
    */
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
 
   /**
-   * Check for an opening [ and start an array iteration.
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
+   * @return whether there is a single token
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  simdjson_inline bool is_single_token() const noexcept;
+
   /**
-   * Check for an opening [ and start an array iteration while at the root.
+   * Assert that there are at least the given number of tokens left.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * Has no effect in release builds.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
   /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
+   * Assert that the given position addresses an actual token (is within bounds).
    *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * Has no effect in release builds.
    */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
   /**
-   * Start an array iteration, after the user has already checked and moved past the [.
+   * Get the JSON text for a given token (relative).
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * The length will include any whitespace at the end of the token.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
-
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * Moves to the next element in an array.
+   * Get a pointer to the current location in the input buffer.
    *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
-
-  /**
-   * Get a child value iterator.
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
    */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
-
-  /** @} */
-
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
   /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
+   * Get the JSON text for a given token.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token to retrieve.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
-
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
-
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
-
-  /** @} */
-protected:
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
+   * Get the maximum length of the JSON text for the current token (or relative).
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
+   * Get the maximum length of the JSON text for the current root token.
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
+   * Get the JSON text for the last token in the document.
    *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
-
-  /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
-
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
+   */
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
-   *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
-   *
-   * ({"globals":{"a":{"shadowable":[}}}})
+   * Ascend one level.
    *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
+   * Validates that the depth - 1 == parent_depth.
    *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
+   * @param parent_depth the expected parent depth.
+   */
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+
+  /**
+   * Descend one level.
    *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
+   * Validates that the new depth == child_depth.
    *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   * @param child_depth the expected child depth.
    */
-
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
-
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
-
-
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
 
   /**
-   * Advance to a place expecting a value (increasing depth).
-   *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
+   * Get current depth.
    */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
+  simdjson_inline depth_t depth() const noexcept;
 
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
+  /**
+   * Get current (writeable) location in the string buffer.
+   */
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
-  simdjson_inline bool is_at_start() const noexcept;
   /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
   /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
-   *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline bool is_at_key() const noexcept;
-
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
 
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
+  /**
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
+   */
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
 
-  /** @copydoc error_code json_iterator::position() const noexcept; */
   simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  /**
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
+   */
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
+
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
+
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
+   */
+  inline void rewind() noexcept;
+  /**
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
+   */
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
   simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
   simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
 
   friend class document;
+  friend class document_stream;
   friend class object;
   friend class array;
   friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
   friend class field;
-}; // value_iterator
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
 
 } // namespace ondemand
 } // namespace icelake
@@ -68559,917 +67795,796 @@ class value_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<icelake::ondemand::value_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::value_iterator> {
+struct simdjson_result<icelake::ondemand::json_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::json_iterator> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::json_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+
   simdjson_inline simdjson_result() noexcept = default;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for icelake */
-/* including simdjson/generic/ondemand/value.h for icelake: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for icelake */
+/* including simdjson/generic/ondemand/json_type.h for icelake: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <type_traits>
-
 namespace simdjson {
-
 namespace icelake {
 namespace ondemand {
+
 /**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
+ * The type of a JSON value.
  */
-class value {
-public:
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
+
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
+
   /**
-   * Create a new invalid value.
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  simdjson_inline value() noexcept = default;
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
+   */
+  simdjson_inline bool is_uint64() const noexcept;
+  /**
+   * return the value as a uint64_t, only valid if is_uint64() is true.
+   */
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
    */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-
+  simdjson_inline bool is_double() const noexcept;
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   * return the value as a double, only valid if is_double() is true.
    */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
    */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
+  simdjson_inline double as_double() const noexcept;
+
 
+protected:
   /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
   /**
-   * Cast this JSON value (inside string) to a unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * End of friend declarations.
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
   /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
+};
+
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
+#endif
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<icelake::ondemand::json_type> : public icelake::implementation_simdjson_result_base<icelake::ondemand::json_type> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for icelake */
+/* including simdjson/generic/ondemand/raw_json_string.h for icelake: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
+/**
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
+ *
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
+ *
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
+ *
+ */
+class raw_json_string {
+public:
   /**
-   * Cast this JSON value (inside string) to a signed integer.
+   * Create a new invalid raw_json_string.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * Cast this JSON value to a double.
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * The given location must be just *after* the beginning quote (") in the JSON file.
+   *
+   * It *must* be terminated by a ", and be a valid JSON string.
    */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
   /**
-   * Cast this JSON value (inside string) to a double
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
    */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline const char * raw() const noexcept;
 
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
    *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
 
   /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
    *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
 
   /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
 
   /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline bool is_equal(const char* target) const noexcept;
 
   /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
    */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
+
+private:
+
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
    */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline void consume() noexcept { buf = nullptr; }
+
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   * Checks whether the inner pointer is non-null and thus usable.
    */
-  simdjson_inline operator array() noexcept(false);
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
+   * ## IMPORTANT: string_view lifetime
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
+   * The string_view is only valid until the next parse() call on the parser.
    *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
+   * ## IMPORTANT: string_view lifetime
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * The string_view is only valid until the next parse() call on the parser.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
+  friend class object;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
+};
+
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<icelake::ondemand::raw_json_string> : public icelake::implementation_simdjson_result_base<icelake::ondemand::raw_json_string> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for icelake */
+/* including simdjson/generic/ondemand/parser.h for icelake: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <memory>
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+/**
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
+ */
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
+ *
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
+ */
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
+public:
   /**
-   * Cast this JSON value to a bool.
+   * Create a JSON parser.
    *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * The new parser will have zero capacity.
    */
-  simdjson_inline operator bool() noexcept(false);
-#endif
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
   /**
-   * Begin array iteration.
+   * Start iterating an on-demand JSON document.
    *
-   * Part of the std::iterable interface.
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
    *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
    *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * ### IMPORTANT: Validate what you use
    *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
    *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
+   * ### IMPORTANT: Document Lifetime
    *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * ### REQUIRED: Buffer Padding
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * ### std::string references
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
    *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
 
   /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * @private
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * Start iterating an on-demand JSON document.
    *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   *   ondemand::parser parser;
+   *   json_iterator doc = parser.iterate(json);
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  /**
-   * Checks whether the value is a string.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the value is a negative number.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
+   * ### IMPORTANT: Document Lifetime
    *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
    *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
+   * ### REQUIRED: Buffer Padding
    *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
+   * @param json The JSON to parse.
    *
-   * @returns the type of the number
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+
 
   /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
+   * Parse a buffer containing many JSON documents.
    *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
    *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
+   * No copy of the input buffer is made.
    *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
    *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
    *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
+   * ### Format
    *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
    *
-   * The string_view will always point into the input buffer.
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
    *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
    *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
    *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
+   * ### REQUIRED: Buffer Padding
    *
-   * See also value::raw_json().
-   */
-  simdjson_inline std::string_view raw_json_token() noexcept;
-
-  /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
-
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
+   * ### Threads
    *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
-   *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * ### Parser Capacity
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
-
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
 
-protected:
-  /**
-   * Create a value.
-   */
-  simdjson_inline value(const value_iterator &iter) noexcept;
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
 
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Skip this value, allowing iteration to continue.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    */
-  simdjson_inline void skip() noexcept;
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
 
   /**
-   * Start a value at the current position.
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
    *
-   * (It should already be started; this is just a self-documentation method.)
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   *
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
 
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * Resume a value.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
-
+  bool threaded{true};
+  #else
   /**
-   * Get the object, starting or resuming it as necessary
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
-
-  value_iterator iter{};
-
-  friend class document;
-  friend class array_iterator;
-  friend class field;
-  friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
-  friend class field;
-};
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<icelake::ondemand::value> : public icelake::implementation_simdjson_result_base<icelake::ondemand::value> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::value &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() noexcept;
-
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
-
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator icelake::ondemand::array() noexcept(false);
-  simdjson_inline operator icelake::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
-
+  bool threaded{false};
+  #endif
   /**
-   * Look up a field by name on an object (order-sensitive).
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
+   * ## IMPORTANT: string_view lifetime
    *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * The string_view is only valid as long as the bytes in dst.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
 
   /**
-   * Look up a field by name on an object, without regard to key order.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * ## IMPORTANT: string_view lifetime
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
+   * The string_view is only valid as long as the bytes in dst.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<icelake::ondemand::value> operator[](int) noexcept = delete;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
 
+#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Get the type of this JSON value.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
    */
-  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
+#endif
 
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+private:
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  std::unique_ptr<token_position[]> start_positions{};
+#endif
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+  friend class json_iterator;
+  friend class document_stream;
 };
 
+} // namespace ondemand
+} // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for icelake */
-/* including simdjson/generic/ondemand/logger.h for icelake: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
 namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
+template<>
+struct simdjson_result<icelake::ondemand::parser> : public icelake::implementation_simdjson_result_base<icelake::ondemand::parser> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::parser &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 };
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
-#endif
-
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
-
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
-
-} // namespace logger
-} // namespace ondemand
-} // namespace icelake
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for icelake */
-/* including simdjson/generic/ondemand/token_iterator.h for icelake: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for icelake */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for icelake: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -69477,130 +68592,179 @@ namespace icelake {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
- *
- * @private This is not intended for external use.
+ * A forward-only JSON array.
  */
-class token_iterator {
+class array {
 public:
   /**
-   * Create a new invalid token_iterator.
+   * Create a new invalid array.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  simdjson_inline array() noexcept = default;
 
   /**
-   * Advance to the next token (returning the current one).
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
   /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline uint32_t current_offset() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
   /**
-   * Get the JSON text for a given token (relative).
-   *
-   * This is not null-terminated; it is a view into the JSON.
-   *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Get the maximum length of the JSON text for a given token.
-   *
-   * The length will include any whitespace at the end of the token.
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * @returns true if the array contains some elements (not empty)
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
-
+  inline simdjson_result<bool> reset() & noexcept;
   /**
-   * Get the JSON text for a given token.
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
    *
-   * @param position The position of the token.
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
    *
-   */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for a given token.
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
    *
-   * The length will include any whitespace at the end of the token.
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
    *
-   * @param position The position of the token.
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a root token.
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
    *
-   * The length will include any whitespace at the end of the token.
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
    *
-   * @param position The position of the token (start of the document).
-   */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
   /**
-   * Return the current index.
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline token_position position() const noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
   /**
-   * Reset to a previously saved index.
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
-
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
-
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
-
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
 protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+  /**
+   * Go to the end of the array, no matter where you are right now.
+   */
+  simdjson_inline error_code consume() noexcept;
 
   /**
-   * Get the index of the JSON text for a given token (relative).
+   * Begin array iteration.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   */
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  /**
+   * Begin array iteration from the root.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
   /**
-   * Get the index of the JSON text for a given token.
+   * Begin array iteration.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
    *
-   * @param position The position of the token.
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   */
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+
+  /**
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
    *
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+  simdjson_inline array(const value_iterator &iter) noexcept;
 
-  const uint8_t *buf{};
-  token_position _position{};
+  /**
+   * Iterator marking current position.
+   *
+   * iter.is_alive() == false indicates iteration is complete.
+   */
+  value_iterator iter{};
 
-  friend class json_iterator;
-  friend class value_iterator;
-  friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
 };
 
 } // namespace ondemand
@@ -69610,708 +68774,1006 @@ class token_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<icelake::ondemand::token_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::token_iterator> {
+struct simdjson_result<icelake::ondemand::array> : public icelake::implementation_simdjson_result_base<icelake::ondemand::array> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::array &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for icelake */
-/* including simdjson/generic/ondemand/json_iterator.h for icelake: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for icelake */
+/* including simdjson/generic/ondemand/array_iterator.h for icelake: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
+ * A forward-only JSON array.
  *
- * @private This is not intended for external use.
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
  */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
+class array_iterator {
+public:
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
+
+  //
+  // Iterator interface
+  //
+
   /**
-   * Next free location in the string buffer.
+   * Get the current element.
    *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
+   * Part of the std::iterator interface.
    */
-  uint8_t *_string_buf_loc{};
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
   /**
-   * JSON error, if there is one.
+   * Check if we are at the end of the JSON.
    *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
+   * Part of the std::iterator interface.
    *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
+   * @return true if there are no more elements in the JSON array.
    */
-  error_code error{SUCCESS};
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
   /**
-   * Depth of the current token in the JSON.
+   * Check if there are more elements in the JSON array.
    *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are more elements in the JSON array.
    */
-  token_position _root{};
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
   /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
    */
-  bool _streaming{false};
+  simdjson_inline array_iterator &operator++() noexcept;
+
+private:
+  value_iterator iter{};
+
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
+};
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
 
+template<>
+struct simdjson_result<icelake::ondemand::array_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator> {
 public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
+  simdjson_inline simdjson_result(icelake::ondemand::array_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-  /**
-   * Tell whether the iterator is still at the start
-   */
-  simdjson_inline bool at_root() const noexcept;
+  //
+  // Iterator interface
+  //
 
-  /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
-   */
-  simdjson_inline bool streaming() const noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<icelake::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<icelake::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &operator++() noexcept;
+};
 
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for icelake */
+/* including simdjson/generic/ondemand/document.h for icelake: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+/**
+ * A JSON document. It holds a json_iterator instance.
+ *
+ * Used by tokens to get text, and string buffer location.
+ *
+ * You must keep the document around during iteration.
+ */
+class document {
+public:
   /**
-   * Get the root value iterator
+   * Create a new invalid document.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline token_position root_position() const noexcept;
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
+
   /**
-   * Assert that we are at the document depth (== 1)
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline void assert_at_document_depth() const noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
   /**
-   * Assert that we are at the root of the document
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline void assert_at_root() const noexcept;
-
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
   /**
-   * Tell whether the iterator is at the EOF mark
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool at_end() const noexcept;
-
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
   /**
-   * Tell whether the iterator is live (has not been moved).
+   * Cast this JSON value (inside string) to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool is_alive() const noexcept;
-
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
   /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline void abandon() noexcept;
-
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
   /**
-   * Advance the current token without modifying depth.
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
-
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Cast this JSON value to a double.
    *
-   * @return whether there is a single token
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline bool is_single_token() const noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * Assert that there are at least the given number of tokens left.
+   * Cast this JSON value (inside string) to a double.
    *
-   * Has no effect in release builds.
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
   /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * Cast this JSON value to a string.
    *
-   * Has no effect in release builds.
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: Calling get_string() twice on the same document is an error.
+   *
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
   /**
-   * Get the JSON text for a given token (relative).
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * Cast this JSON value to a string.
    *
-   * The length will include any whitespace at the end of the token.
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
   /**
-   * Get a pointer to the current location in the input buffer.
+   * Cast this JSON value to a raw_json_string.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
   /**
-   * Get the JSON text for a given token.
+   * Cast this JSON value to a bool.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
    *
-   * @param position The position of the token to retrieve.
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
-   *
-   * The length will include any whitespace at the end of the token.
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   * @param position The position of the token to retrieve.
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
   /**
-   * Get the maximum length of the JSON text for the current root token.
+   * Get this value as the given type.
    *
-   * The length will include any whitespace at the end of the token.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * @param position The position of the token to retrieve.
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
   /**
-   * Get the JSON text for the last token in the document.
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
    */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
   /**
-   * Ascend one level.
+   * Get this value as the given type.
    *
-   * Validates that the depth - 1 == parent_depth.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
    *
-   * @param parent_depth the expected parent depth.
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
+#if SIMDJSON_EXCEPTIONS
   /**
-   * Descend one level.
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
    *
-   * Validates that the new depth == child_depth.
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * @param child_depth the expected child depth.
+   * @returns An instance of type T
    */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
 
   /**
-   * Get current depth.
-   */
-  simdjson_inline depth_t depth() const noexcept;
-
-  /**
-   * Get current (writeable) location in the string buffer.
-   */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-
-  /**
-   * Report an unrecoverable error, preventing further iteration.
+   * Cast this JSON value to an array.
    *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
    */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
+  simdjson_inline operator array() & noexcept(false);
   /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
    */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
-
+  simdjson_inline operator object() & noexcept(false);
   /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
-
-  simdjson_inline token_position position() const noexcept;
+  simdjson_inline operator uint64_t() noexcept(false);
   /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
-
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
-
-  simdjson_inline error_code consume_character(char c) noexcept;
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
-#endif
-
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-
+  simdjson_inline operator int64_t() noexcept(false);
   /**
-   * Returns the current location in the document if in bounds.
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
+  simdjson_inline operator double() noexcept(false);
   /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  inline void rewind() noexcept;
+  simdjson_inline operator std::string_view() noexcept(false);
   /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
-
-  friend class document;
-  friend class document_stream;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<icelake::ondemand::json_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::json_iterator> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::json_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for icelake */
-/* including simdjson/generic/ondemand/json_type.h for icelake: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-/**
- * The type of a JSON value.
- */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
-
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
- */
-struct number {
-
+  simdjson_inline operator raw_json_string() noexcept(false);
   /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+   * Cast this JSON value to a bool.
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  simdjson_inline operator bool() noexcept(false);
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
    */
-  simdjson_inline bool is_uint64() const noexcept;
+  simdjson_inline operator value() noexcept(false);
+#endif
   /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
-  /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline bool is_int64() const noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
   /**
-   * return the value as a int64_t, only valid if is_int64() is true.
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
-
-
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline bool is_double() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
   /**
-   * return the value as a double, only valid if is_double() is true.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
 
   /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline double as_double() const noexcept;
-
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
 
-protected:
-  /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
-   */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
   /**
-   * End of friend declarations.
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
-
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
-
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<icelake::ondemand::json_type> : public icelake::implementation_simdjson_result_base<icelake::ondemand::json_type> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::json_type &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for icelake */
-/* including simdjson/generic/ondemand/raw_json_string.h for icelake: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
-/**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
- *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
- *
- */
-class raw_json_string {
-public:
   /**
-   * Create a new invalid raw_json_string.
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline raw_json_string() noexcept = default;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
 
   /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
-   *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
+   * Checks whether the document is a string.
    *
-   * It *must* be terminated by a ", and be a valid JSON string.
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
   /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
+   * Checks whether the document is a negative number.
    *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
+   * @returns true if the number if negative.
    */
-  simdjson_inline const char * raw() const noexcept;
-
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
-   *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * @returns true if the number if negative.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
-
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
-   *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
    */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
    */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
 
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
    */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
-
+  inline void rewind() noexcept;
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Returns debugging information.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
-
-private:
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
 
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
 
   /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
    */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
+  inline bool at_end() const noexcept;
 
   /**
-   * Checks whether the inner pointer is non-null and thus usable.
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+  simdjson_inline int32_t current_depth() const noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
-   * ## IMPORTANT: string_view lifetime
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * It is allowed for a key to be the empty string:
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
    *
-   * ## IMPORTANT: string_view lifetime
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
    *
-   * The string_view is only valid until the next parse() call on the parser.
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
    *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
+  /**
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+protected:
+  /**
+   * Consumes the document.
+   */
+  simdjson_inline error_code consume() noexcept;
+
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
+
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
+
+  //
+  // Fields
+  //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+
+  friend class array_iterator;
+  friend class value;
+  friend class ondemand::parser;
   friend class object;
+  friend class array;
   friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
 };
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
 
 /**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+class document_reference {
+public:
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
+
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
+
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
+private:
+  document *doc{nullptr};
+};
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
@@ -70319,709 +69781,587 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
 namespace simdjson {
 
 template<>
-struct simdjson_result<icelake::ondemand::raw_json_string> : public icelake::implementation_simdjson_result_base<icelake::ondemand::raw_json_string> {
+struct simdjson_result<icelake::ondemand::document> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::document &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+  simdjson_inline error_code rewind() noexcept;
 
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document>::value == false>::type>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator icelake::ondemand::array() & noexcept(false);
+  simdjson_inline operator icelake::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator icelake::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
 };
 
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for icelake */
-/* including simdjson/generic/ondemand/parser.h for icelake: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+} // namespace simdjson
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
 
 namespace simdjson {
-namespace icelake {
-namespace ondemand {
 
-/**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
- *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
-
-/**
- * A JSON fragment iterator.
- *
- * This holds the actual iterator as well as the buffer for writing strings.
- */
-class parser {
+template<>
+struct simdjson_result<icelake::ondemand::document_reference> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document_reference> {
 public:
-  /**
-   * Create a JSON parser.
-   *
-   * The new parser will have zero capacity.
-   */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+  simdjson_inline simdjson_result(icelake::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
 
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
 
-  /**
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
-   *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
-   *
-   * ### IMPORTANT: Validate what you use
-   *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
-   *
-   * ### IMPORTANT: Document Lifetime
-   *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * ### std::string references
-   *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
-   *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
-   *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
-   *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
-   *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
-   */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator icelake::ondemand::array() & noexcept(false);
+  simdjson_inline operator icelake::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator icelake::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
 
-  /**
-   * @private
-   *
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
-   *
-   * ### IMPORTANT: Document Lifetime
-   *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
-   *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * @param json The JSON to parse.
-   *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
-   */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
 
 
-  /**
-   * Parse a buffer containing many JSON documents.
-   *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
-   *
-   * No copy of the input buffer is made.
-   *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
-   *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
-   *
-   * ### Format
-   *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
-   *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
-   *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
-   *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * ### Threads
-   *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
-   *
-   * ### Parser Capacity
-   *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
-   *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
-   */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+} // namespace simdjson
 
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+/* end file simdjson/generic/ondemand/document.h for icelake */
+/* including simdjson/generic/ondemand/document_stream.h for icelake: #include "simdjson/generic/ondemand/document_stream.h" */
+/* begin file simdjson/generic/ondemand/document_stream.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
-  /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
-   */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
-   *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
-   *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
-   */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
 
-  #ifdef SIMDJSON_THREADS_ENABLED
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+/** @private Custom worker class **/
+struct stage1_worker {
+  stage1_worker() noexcept = default;
+  stage1_worker(const stage1_worker&) = delete;
+  stage1_worker(stage1_worker&&) = delete;
+  stage1_worker operator=(const stage1_worker&) = delete;
+  ~stage1_worker();
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
-   */
-  bool threaded{true};
-  #else
+   * We only start the thread when it is needed, not at object construction, this may throw.
+   * You should only call this once.
+   **/
+  void start_thread();
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Start a stage 1 job. You should first call 'run', then 'finish'.
+   * You must call start_thread once before.
    */
-  bool threaded{false};
-  #endif
+  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
+  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
+  void finish();
+
+private:
+
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid as long as the bytes in dst.
-   *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
+   * Normally, we would never stop the thread. But we do in the destructor.
+   * This function is only safe assuming that you are not waiting for results. You
+   * should have called run, then finish, and be done.
+   **/
+  void stop_thread();
 
+  std::thread thread{};
+  /** These three variables define the work done by the thread. **/
+  ondemand::parser * stage1_thread_parser{};
+  size_t _next_batch_start{};
+  document_stream * owner{};
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid as long as the bytes in dst.
-   *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * We have two state variables. This could be streamlined to one variable in the future but
+   * we use two for clarity.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
+  bool has_work{false};
+  bool can_work{true};
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
+   * We lock using a mutex.
    */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
-
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
+  std::mutex locking_mutex{};
+  std::condition_variable cond_var{};
 
-  friend class json_iterator;
   friend class document_stream;
 };
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<icelake::ondemand::parser> : public icelake::implementation_simdjson_result_base<icelake::ondemand::parser> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::parser &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for icelake */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for icelake: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+#endif  // SIMDJSON_THREADS_ENABLED
 
 /**
- * A forward-only JSON array.
+ * A forward-only stream of documents.
+ *
+ * Produced by parser::iterate_many.
+ *
  */
-class array {
+class document_stream {
 public:
   /**
-   * Create a new invalid array.
+   * Construct an uninitialized document_stream.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   *  ```c++
+   *  document_stream docs;
+   *  auto error = parser.iterate_many(json).get(docs);
+   *  ```
    */
-  simdjson_inline array() noexcept = default;
+  simdjson_inline document_stream() noexcept;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream(document_stream &&other) noexcept = default;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+
+  simdjson_inline ~document_stream() noexcept;
 
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * Returns the input size in bytes.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  inline size_t size_in_bytes() const noexcept;
+
   /**
-   * Sentinel representing the end of the array.
+   * After iterating through the stream, this method
+   * returns the number of bytes that were not parsed at the end
+   * of the stream. If truncated_bytes() differs from zero,
+   * then the input was truncated maybe because incomplete JSON
+   * documents were found at the end of the stream. You
+   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
    *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * You should only call truncated_bytes() after streaming through all
+   * documents, like so:
    *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
-  /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   *   document_stream stream = parser.iterate_many(json,window);
+   *   for(auto & doc : stream) {
+   *      // do something with doc
+   *   }
+   *   size_t truncated = stream.truncated_bytes();
    *
-   * @returns true if the array contains some elements (not empty)
    */
-  inline simdjson_result<bool> reset() & noexcept;
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  inline size_t truncated_bytes() const noexcept;
 
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
 
-  /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
+
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
+
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
+
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
+
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
 
   /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Start iterating the documents in the stream.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-protected:
+  simdjson_inline iterator begin() noexcept;
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * The end of the stream, for iterator comparison purposes.
    */
-  simdjson_inline error_code consume() noexcept;
+  simdjson_inline iterator end() noexcept;
+
+private:
+
+  document_stream &operator=(const document_stream &) = delete; // Disallow copying
+  document_stream(const document_stream &other) = delete; // Disallow copying
 
   /**
-   * Begin array iteration.
+   * Construct a document_stream. Does not allocate or parse anything until the iterator is
+   * used.
    *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @param parser is a reference to the parser instance used to generate this document_stream
+   * @param buf is the raw byte buffer we need to process
+   * @param len is the length of the raw byte buffer in bytes
+   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
    */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  simdjson_inline document_stream(
+    ondemand::parser &parser,
+    const uint8_t *buf,
+    size_t len,
+    size_t batch_size,
+    bool allow_comma_separated
+  ) noexcept;
+
   /**
-   * Begin array iteration from the root.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   * Parse the first document in the buffer. Used by begin(), to handle allocation and
+   * initialization.
    */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  inline void start() noexcept;
+
   /**
-   * Begin array iteration.
+   * Parse the next document found in the buffer previously given to document_stream.
    *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
+   * The content should be a valid JSON document encoded as UTF-8. If there is a
+   * UTF-8 BOM, the parser skips it.
    *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   * You do NOT need to pre-allocate a parser.  This function takes care of
+   * pre-allocating a capacity defined by the batch_size defined when creating the
+   * document_stream object.
+   *
+   * The function returns simdjson::EMPTY if there is no more data to be parsed.
+   *
+   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
+   * and indicates that the buffer has successfully been parsed to the end.
+   * Every document it contained has been parsed without error.
+   *
+   * The function returns an error code from simdjson/simdjson.h in case of failure
+   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
+   * the simdjson::error_message function converts these error codes into a string).
+   *
+   * You can also check validity by calling parser.is_valid(). The same parser can
+   * and should be reused for the other documents in the buffer.
    */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+  inline void next() noexcept;
+
+  /** Move the json_iterator of the document to the location of the next document in the stream. */
+  inline void next_document() noexcept;
+
+  /** Get the next document index. */
+  inline size_t next_batch_start() const noexcept;
+
+  /** Pass the next batch through stage 1 with the given parser. */
+  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
 
+  // Fields
+  ondemand::parser *parser;
+  const uint8_t *buf;
+  size_t len;
+  size_t batch_size;
+  bool allow_comma_separated;
   /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
-   *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
+   * We are going to use just one document instance. The document owns
+   * the json_iterator. It implies that we only ever pass a reference
+   * to the document to the users.
    */
-  simdjson_inline array(const value_iterator &iter) noexcept;
+  document doc{};
+  /** The error (or lack thereof) from the current document. */
+  error_code error;
+  size_t batch_start{0};
+  size_t doc_index{};
+
+  #ifdef SIMDJSON_THREADS_ENABLED
+  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
+  bool use_thread;
+
+  inline void load_from_stage1_thread() noexcept;
+
+  /** Start a thread to run stage 1 on the next batch. */
+  inline void start_stage1_thread() noexcept;
+
+  /** Wait for the stage 1 thread to finish and capture the results. */
+  inline void finish_stage1_thread() noexcept;
 
+  /** The error returned from the stage 1 thread. */
+  error_code stage1_thread_error{UNINITIALIZED};
+  /** The thread used to run stage 1 against the next batch in the background. */
+  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
   /**
-   * Iterator marking current position.
-   *
-   * iter.is_alive() == false indicates iteration is complete.
+   * The parser used to run stage 1 in the background. Will be swapped
+   * with the regular parser when finished.
    */
-  value_iterator iter{};
+  ondemand::parser stage1_thread_parser{};
 
-  friend class value;
+  friend struct stage1_worker;
+  #endif // SIMDJSON_THREADS_ENABLED
+
+  friend class parser;
   friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
-  friend class array_iterator;
-};
+  friend class json_iterator;
+  friend struct simdjson_result<ondemand::document_stream>;
+  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
+};  // document_stream
 
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
 namespace simdjson {
-
 template<>
-struct simdjson_result<icelake::ondemand::array> : public icelake::implementation_simdjson_result_base<icelake::ondemand::array> {
+struct simdjson_result<icelake::ondemand::document_stream> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document_stream> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::array &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::document_stream &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for icelake */
-/* including simdjson/generic/ondemand/array_iterator.h for icelake: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+/* end file simdjson/generic/ondemand/document_stream.h for icelake */
+/* including simdjson/generic/ondemand/field.h for icelake: #include "simdjson/generic/ondemand/field.h" */
+/* begin file simdjson/generic/ondemand/field.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
 /**
- * A forward-only JSON array.
+ * A JSON field (key/value pair) in an object.
  *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
+ * Returned from object iteration.
+ *
+ * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
  */
-class array_iterator {
+class field : public std::pair<raw_json_string, value> {
 public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
   /**
-   * Get the current element.
+   * Create a new invalid field.
    *
-   * Part of the std::iterator interface.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline field() noexcept;
+
   /**
-   * Check if we are at the end of the JSON.
-   *
-   * Part of the std::iterator interface.
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it.
    *
-   * @return true if there are no more elements in the JSON array.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
   /**
-   * Check if there are more elements in the JSON array.
-   *
-   * Part of the std::iterator interface.
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it. The content is stored in the receiver.
    *
-   * @return true if there are more elements in the JSON array.
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
    */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  template <typename string_type>
+  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * Move to the next element.
-   *
-   * Part of the std::iterator interface.
+   * Get the key as a raw_json_string. Can be used for direct comparison with
+   * an unescaped C string: e.g., key() == "test". This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key() for a similar function which returns
+   * a more convenient std::string_view result.
    */
-  simdjson_inline array_iterator &operator++() noexcept;
-
-private:
-  value_iterator iter{};
-
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+  simdjson_inline raw_json_string key() const noexcept;
+  /**
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
+   */
+  simdjson_inline std::string_view key_raw_json_token() const noexcept;
+  /**
+   * Get the key as a string_view. This does not include the quotes and
+   * the string is unprocessed key so it may contain escape characters
+   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
+   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
+   */
+  simdjson_inline std::string_view escaped_key() const noexcept;
+  /**
+   * Get the field value.
+   */
+  simdjson_inline ondemand::value &value() & noexcept;
+  /**
+   * @overload ondemand::value &ondemand::value() & noexcept
+   */
+  simdjson_inline ondemand::value value() && noexcept;
 
-  friend class array;
-  friend class value;
-  friend struct simdjson_result<array_iterator>;
+protected:
+  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
+  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
+  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
+  friend struct simdjson_result<field>;
+  friend class object_iterator;
 };
 
 } // namespace ondemand
@@ -71031,389 +70371,207 @@ class array_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<icelake::ondemand::array_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator> {
+struct simdjson_result<icelake::ondemand::field> : public icelake::implementation_simdjson_result_base<icelake::ondemand::field> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::array_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::field &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
 
-  //
-  // Iterator interface
-  //
-
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<icelake::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<icelake::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &operator++() noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  template<typename string_type>
+  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> value() noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for icelake */
-/* including simdjson/generic/ondemand/document.h for icelake: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+/* end file simdjson/generic/ondemand/field.h for icelake */
+/* including simdjson/generic/ondemand/object.h for icelake: #include "simdjson/generic/ondemand/object.h" */
+/* begin file simdjson/generic/ondemand/object.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
- *
- * Used by tokens to get text, and string buffer location.
- *
- * You must keep the document around during iteration.
+ * A forward-only JSON object field iterator.
  */
-class document {
+class object {
 public:
   /**
-   * Create a new invalid document.
+   * Create a new invalid object.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
+  simdjson_inline object() noexcept = default;
 
+  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<object_iterator> end() noexcept;
   /**
-   * Cast this JSON value to an array.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  /**
-   * Cast this JSON value to an object.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  /**
-   * Cast this JSON value to an unsigned integer.
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to an unsigned integer.
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a signed integer.
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * You are expected to access keys only once. You should access the value corresponding to a
+   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
+
   /**
-   * Cast this JSON value (inside string) to a signed integer.
+   * Look up a field by name on an object, without regard to key order.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: Calling get_string() twice on the same document is an error.
-   *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  /**
-   * Cast this JSON value to a bool.
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
    *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
+   * If you expect to have keys with escape characters, please review our documentation.
    *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   * Get the value associated with the given JSON pointer. We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
    *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   * It is allowed for a key to be the empty string:
    *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
    *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
+   * instance: there is no rewind and no invalidation.
    *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
    *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
    *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
    *
-   * @returns An instance of type T
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
-  template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() & noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline operator double() noexcept(false);
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
-   */
-  simdjson_inline operator bool() noexcept(false);
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the object. You should still consume values only once even if you
+   * can iterate through the object more than once. If you unescape a string or a key
+   * within the object more than once, you have unsafe code. Note that rewinding an object
+   * means that you may need to reparse it anew: it is not a free operation.
    *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * @returns true if the object contains some elements (not empty)
    */
-  simdjson_inline operator value() noexcept(false);
-#endif
+  inline simdjson_result<bool> reset() & noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
+   * This method scans the beginning of the object and checks whether the
+   * object is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the object is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * safe to continue.
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
+  inline simdjson_result<bool> is_empty() & noexcept;
+  /**
    * This method scans the object and counts the number of key-value pairs.
    * The count_fields method should always be called before you have begun
    * iterating through the object: it is expected that you are pointing at
@@ -71426,510 +70584,125 @@ class document {
    *
    * To check that an object is empty, it is more performant to use
    * the is_empty() method.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * Consumes the object and returns a string_view instance corresponding to the
+   * object as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+protected:
   /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
+   * Go to the end of the object, no matter where you are right now.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline error_code consume() noexcept;
+  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
+  static simdjson_inline object resume(const value_iterator &iter) noexcept;
+  simdjson_inline object(const value_iterator &iter) noexcept;
+
+  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+
+  value_iterator iter{};
+
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<object>;
+};
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<icelake::ondemand::object> : public icelake::implementation_simdjson_result_base<icelake::ondemand::object> {
+public:
+  simdjson_inline simdjson_result(icelake::ondemand::object &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> end() noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+
+  inline simdjson_result<bool> reset() noexcept;
+  inline simdjson_result<bool> is_empty() noexcept;
+  inline simdjson_result<size_t> count_fields() & noexcept;
+  inline simdjson_result<std::string_view> raw_json() noexcept;
+
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+/* end file simdjson/generic/ondemand/object.h for icelake */
+/* including simdjson/generic/ondemand/object_iterator.h for icelake: #include "simdjson/generic/ondemand/object_iterator.h" */
+/* begin file simdjson/generic/ondemand/object_iterator.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+class object_iterator {
+public:
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
-   * is an error.
+   * Create a new invalid object_iterator.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline object_iterator() noexcept = default;
 
+  //
+  // Iterator interface
+  //
+
+  // Reads key and value, yielding them to the user.
+  // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline simdjson_result<field> operator*() noexcept;
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const object_iterator &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline object_iterator &operator++() noexcept;
+
+private:
   /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
+   * The underlying JSON iterator.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
+   * is first used, and never changes afterwards.
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
-
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
-   */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-protected:
-  /**
-   * Consumes the document.
-   */
-  simdjson_inline error_code consume() noexcept;
-
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
-
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
+  value_iterator iter{};
 
-  friend class array_iterator;
-  friend class value;
-  friend class ondemand::parser;
+  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
+  friend struct simdjson_result<object_iterator>;
   friend class object;
-  friend class array;
-  friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
 };
 
-
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-private:
-  document *doc{nullptr};
-};
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
@@ -71937,588 +70710,588 @@ class document_reference {
 namespace simdjson {
 
 template<>
-struct simdjson_result<icelake::ondemand::document> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document> {
+struct simdjson_result<icelake::ondemand::object_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::object_iterator> {
 public:
-  simdjson_inline simdjson_result(icelake::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(icelake::ondemand::object_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
 
-  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document>::value == false>::type>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator icelake::ondemand::array() & noexcept(false);
-  simdjson_inline operator icelake::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator icelake::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool at_end() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  //
+  // Iterator interface
+  //
 
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+  // Reads key and value, yielding them to the user.
+  simdjson_inline simdjson_result<icelake::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const simdjson_result<icelake::ondemand::object_iterator> &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const simdjson_result<icelake::ondemand::object_iterator> &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &operator++() noexcept;
 };
 
-
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+/* end file simdjson/generic/ondemand/object_iterator.h for icelake */
+/* including simdjson/generic/ondemand/serialization.h for icelake: #include "simdjson/generic/ondemand/serialization.h" */
+/* begin file simdjson/generic/ondemand/serialization.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+/**
+ * Create a string-view instance out of a document instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept;
+/**
+ * Create a string-view instance out of a value instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. The value must
+ * not have been accessed previously. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept;
+/**
+ * Create a string-view instance out of an object instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept;
+/**
+ * Create a string-view instance out of an array instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x);
+} // namespace simdjson
 
-template<>
-struct simdjson_result<icelake::ondemand::document_reference> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document_reference> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::document_reference value, error_code error) noexcept;
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<icelake::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+/**
+ * We want to support argument-dependent lookup (ADL).
+ * Hence we should define operator<< in the namespace
+ * where the argument (here value, object, etc.) resides.
+ * Credit: @madhur4127
+ * See https://github.com/simdjson/simdjson/issues/1768
+ */
+namespace simdjson { namespace icelake { namespace ondemand {
 
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+/**
+ * Print JSON to an output stream.  It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The element.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x);
 #if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator icelake::ondemand::array() & noexcept(false);
-  simdjson_inline operator icelake::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator icelake::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator icelake::ondemand::value() noexcept(false);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x);
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<icelake::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<icelake::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
-
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x);
+#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The object.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::object> x);
+#endif
+}}} // namespace simdjson::icelake::ondemand
 
-} // namespace simdjson
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+/* end file simdjson/generic/ondemand/serialization.h for icelake */
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-/* end file simdjson/generic/ondemand/document.h for icelake */
-/* including simdjson/generic/ondemand/document_stream.h for icelake: #include "simdjson/generic/ondemand/document_stream.h" */
-/* begin file simdjson/generic/ondemand/document_stream.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+// Deserialization for standard types
+/* including simdjson/generic/ondemand/std_deserialize.h for icelake: #include "simdjson/generic/ondemand/std_deserialize.h" */
+/* begin file simdjson/generic/ondemand/std_deserialize.h for icelake */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
+#include <concepts>
+#include <limits>
 
 namespace simdjson {
-namespace icelake {
-namespace ondemand {
+template <typename T>
+constexpr bool require_custom_serialization = false;
 
-#ifdef SIMDJSON_THREADS_ENABLED
-/** @private Custom worker class **/
-struct stage1_worker {
-  stage1_worker() noexcept = default;
-  stage1_worker(const stage1_worker&) = delete;
-  stage1_worker(stage1_worker&&) = delete;
-  stage1_worker operator=(const stage1_worker&) = delete;
-  ~stage1_worker();
-  /**
-   * We only start the thread when it is needed, not at object construction, this may throw.
-   * You should only call this once.
-   **/
-  void start_thread();
-  /**
-   * Start a stage 1 job. You should first call 'run', then 'finish'.
-   * You must call start_thread once before.
-   */
-  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
-  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
-  void finish();
+//////////////////////////////
+// Number deserialization
+//////////////////////////////
 
-private:
+template <std::unsigned_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  /**
-   * Normally, we would never stop the thread. But we do in the destructor.
-   * This function is only safe assuming that you are not waiting for results. You
-   * should have called run, then finish, and be done.
-   **/
-  void stop_thread();
+  uint64_t x;
+  SIMDJSON_TRY(val.get_uint64().get(x));
+  if (x > (limits::max)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  std::thread thread{};
-  /** These three variables define the work done by the thread. **/
-  ondemand::parser * stage1_thread_parser{};
-  size_t _next_batch_start{};
-  document_stream * owner{};
-  /**
-   * We have two state variables. This could be streamlined to one variable in the future but
-   * we use two for clarity.
-   */
-  bool has_work{false};
-  bool can_work{true};
+template <std::floating_point T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  double x;
+  SIMDJSON_TRY(val.get_double().get(x));
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
-  /**
-   * We lock using a mutex.
-   */
-  std::mutex locking_mutex{};
-  std::condition_variable cond_var{};
+template <std::signed_integral T>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
+  using limits = std::numeric_limits<T>;
 
-  friend class document_stream;
-};
-#endif  // SIMDJSON_THREADS_ENABLED
+  int64_t x;
+  SIMDJSON_TRY(val.get_int64().get(x));
+  if (x > (limits::max)() || x < (limits::min)()) {
+    return NUMBER_OUT_OF_RANGE;
+  }
+  out = static_cast<T>(x);
+  return SUCCESS;
+}
 
 /**
- * A forward-only stream of documents.
- *
- * Produced by parser::iterate_many.
- *
+ * STL containers have several constructors including one that takes a single
+ * size argument. Thus, some compilers (Visual Studio) will not be able to
+ * disambiguate between the size and container constructor. Users should
+ * explicitly specify the type of the container as needed: e.g.,
+ * doc.get<std::vector<int>>().
  */
-class document_stream {
-public:
-  /**
-   * Construct an uninitialized document_stream.
-   *
-   *  ```c++
-   *  document_stream docs;
-   *  auto error = parser.iterate_many(json).get(docs);
-   *  ```
-   */
-  simdjson_inline document_stream() noexcept;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream(document_stream &&other) noexcept = default;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
+template <concepts::appendable_containers T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the container must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the container must default constructible.");
 
-  simdjson_inline ~document_stream() noexcept;
+  icelake::ondemand::array arr;
+  SIMDJSON_TRY(val.get_array().get(arr));
+  for (auto v : arr) {
+    if constexpr (concepts::returns_reference<T>) {
+      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
+          err) {
+        // If an error occurs, the empty element that we just inserted gets
+        // removed. We're not using a temp variable because if T is a heavy
+        // type, we want the valid path to be the fast path and the slow path be
+        // the path that has errors in it.
+        if constexpr (requires { out.pop_back(); }) {
+          static_cast<void>(out.pop_back());
+        }
+        return err;
+      }
+    } else {
+      value_type temp;
+      if (auto const err = v.get<value_type>().get(temp); err) {
+        return err;
+      }
+      concepts::emplace_one(out, std::move(temp));
+    }
+  }
+  return SUCCESS;
+}
 
-  /**
-   * Returns the input size in bytes.
-   */
-  inline size_t size_in_bytes() const noexcept;
 
-  /**
-   * After iterating through the stream, this method
-   * returns the number of bytes that were not parsed at the end
-   * of the stream. If truncated_bytes() differs from zero,
-   * then the input was truncated maybe because incomplete JSON
-   * documents were found at the end of the stream. You
-   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
-   *
-   * You should only call truncated_bytes() after streaming through all
-   * documents, like so:
-   *
-   *   document_stream stream = parser.iterate_many(json,window);
-   *   for(auto & doc : stream) {
-   *      // do something with doc
-   *   }
-   *   size_t truncated = stream.truncated_bytes();
-   *
-   */
-  inline size_t truncated_bytes() const noexcept;
 
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
+/**
+ * This CPO (Customization Point Object) will help deserialize into
+ * smart pointers.
+ *
+ * If constructing T is nothrow, this conversion should be nothrow as well since
+ * we return MEMALLOC if we're not able to allocate memory instead of throwing
+ * the error message.
+ *
+ * @tparam T The type inside the smart pointer
+ * @tparam ValT document/value type
+ * @param val document/value
+ * @param out a reference to the smart pointer
+ * @return status of the conversion
+ */
+template <concepts::smart_pointer T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
+  using element_type = typename std::remove_cvref_t<T>::element_type;
 
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
+  // For better error messages, don't use these as constraints on
+  // the tag_invoke CPO.
+  static_assert(
+      deserializable<element_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<element_type>,
+      "The specified type inside the unique_ptr must default constructible.");
 
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
+  auto ptr = new (std::nothrow) element_type();
+  if (ptr == nullptr) {
+    return MEMALLOC;
+  }
+  SIMDJSON_TRY(val.template get<element_type>(*ptr));
+  out.reset(ptr);
+  return SUCCESS;
+}
 
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
+/**
+ * This CPO (Customization Point Object) will help deserialize into optional types.
+ */
+template <concepts::optional_type T, typename ValT>
+  requires(!require_custom_serialization<T>)
+error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
+  using value_type = typename std::remove_cvref_t<T>::value_type;
 
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
+  static_assert(
+      deserializable<value_type, ValT>,
+      "The specified type inside the unique_ptr must itself be deserializable");
+  static_assert(
+      std::is_default_constructible_v<value_type>,
+      "The specified type inside the unique_ptr must default constructible.");
 
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
+  if (!out) {
+    out.emplace();
+  }
+  SIMDJSON_TRY(val.template get<value_type>(out.value()));
+  return SUCCESS;
+}
 
-  /**
-   * Start iterating the documents in the stream.
-   */
-  simdjson_inline iterator begin() noexcept;
-  /**
-   * The end of the stream, for iterator comparison purposes.
-   */
-  simdjson_inline iterator end() noexcept;
+} // namespace simdjson
 
-private:
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+/* end file simdjson/generic/ondemand/std_deserialize.h for icelake */
 
-  document_stream &operator=(const document_stream &) = delete; // Disallow copying
-  document_stream(const document_stream &other) = delete; // Disallow copying
+// Inline definitions
+/* including simdjson/generic/ondemand/array-inl.h for icelake: #include "simdjson/generic/ondemand/array-inl.h" */
+/* begin file simdjson/generic/ondemand/array-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
 
-  /**
-   * Construct a document_stream. Does not allocate or parse anything until the iterator is
-   * used.
-   *
-   * @param parser is a reference to the parser instance used to generate this document_stream
-   * @param buf is the raw byte buffer we need to process
-   * @param len is the length of the raw byte buffer in bytes
-   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
-   */
-  simdjson_inline document_stream(
-    ondemand::parser &parser,
-    const uint8_t *buf,
-    size_t len,
-    size_t batch_size,
-    bool allow_comma_separated
-  ) noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Parse the first document in the buffer. Used by begin(), to handle allocation and
-   * initialization.
-   */
-  inline void start() noexcept;
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
-  /**
-   * Parse the next document found in the buffer previously given to document_stream.
-   *
-   * The content should be a valid JSON document encoded as UTF-8. If there is a
-   * UTF-8 BOM, the parser skips it.
-   *
-   * You do NOT need to pre-allocate a parser.  This function takes care of
-   * pre-allocating a capacity defined by the batch_size defined when creating the
-   * document_stream object.
-   *
-   * The function returns simdjson::EMPTY if there is no more data to be parsed.
-   *
-   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
-   * and indicates that the buffer has successfully been parsed to the end.
-   * Every document it contained has been parsed without error.
-   *
-   * The function returns an error code from simdjson/simdjson.h in case of failure
-   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
-   * the simdjson::error_message function converts these error codes into a string).
-   *
-   * You can also check validity by calling parser.is_valid(). The same parser can
-   * and should be reused for the other documents in the buffer.
-   */
-  inline void next() noexcept;
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the array is first found and the iterator is just past the `{`.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
+//   depth == iter->depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter->depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the array iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
+//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
+//
+// ## Terminal State
+//
+// The terminal state has iter->depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
+//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
+//   error == SUCCESS.
+//
 
-  /** Move the json_iterator of the document to the location of the next document in the stream. */
-  inline void next_document() noexcept;
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
 
-  /** Get the next document index. */
-  inline size_t next_batch_start() const noexcept;
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
+}
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  bool has_value;
+  SIMDJSON_TRY(iter.started_array().get(has_value));
+  return array(iter);
+}
 
-  /** Pass the next batch through stage 1 with the given parser. */
-  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return array_iterator(iter);
+}
+simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
+  return array_iterator(iter);
+}
+simdjson_inline error_code array::consume() noexcept {
+  auto error = iter.json_iter().skip_child(iter.depth()-1);
+  if(error) { iter.abandon(); }
+  return error;
+}
 
-  // Fields
-  ondemand::parser *parser;
-  const uint8_t *buf;
-  size_t len;
-  size_t batch_size;
-  bool allow_comma_separated;
-  /**
-   * We are going to use just one document instance. The document owns
-   * the json_iterator. It implies that we only ever pass a reference
-   * to the document to the users.
-   */
-  document doc{};
-  /** The error (or lack thereof) from the current document. */
-  error_code error;
-  size_t batch_start{0};
-  size_t doc_index{};
+simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
-  bool use_thread;
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the array after counting the number of elements.
+  iter.reset_array();
+  return count;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
 
-  inline void load_from_stage1_thread() noexcept;
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
 
-  /** Start a thread to run stage 1 on the next batch. */
-  inline void start_stage1_thread() noexcept;
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
+}
 
-  /** Wait for the stage 1 thread to finish and capture the results. */
-  inline void finish_stage1_thread() noexcept;
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
 
-  /** The error returned from the stage 1 thread. */
-  error_code stage1_thread_error{UNINITIALIZED};
-  /** The thread used to run stage 1 against the next batch in the background. */
-  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
-  /**
-   * The parser used to run stage 1 in the background. Will be swapped
-   * with the regular parser when finished.
-   */
-  ondemand::parser stage1_thread_parser{};
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
 
-  friend struct stage1_worker;
-  #endif // SIMDJSON_THREADS_ENABLED
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-  friend class parser;
-  friend class document;
-  friend class json_iterator;
-  friend struct simdjson_result<ondemand::document_stream>;
-  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
-};  // document_stream
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
+}
+
+inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+  return at_pointer(json_pointer);
+}
+
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
+  }
+  return INDEX_OUT_OF_BOUNDS;
+}
 
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
 namespace simdjson {
-template<>
-struct simdjson_result<icelake::ondemand::document_stream> : public icelake::implementation_simdjson_result_base<icelake::ondemand::document_stream> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::document_stream &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
 
+simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+  icelake::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::array>(
+      std::forward<icelake::ondemand::array>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+  error_code error
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::array>(error)
+{
+}
+
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
+}
+simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::array>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline  simdjson_result<bool> simdjson_result<icelake::ondemand::array>::is_empty() & noexcept {
+  if (error()) { return error(); }
+  return first.is_empty();
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
+  return first.at_pointer(json_pointer);
+}
+simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
+  return first.at_path(json_path);
+}
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::array>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
-/* end file simdjson/generic/ondemand/document_stream.h for icelake */
-/* including simdjson/generic/ondemand/field.h for icelake: #include "simdjson/generic/ondemand/field.h" */
-/* begin file simdjson/generic/ondemand/field.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for icelake */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-/**
- * A JSON field (key/value pair) in an object.
- *
- * Returned from object iteration.
- *
- * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
- */
-class field : public std::pair<raw_json_string, value> {
-public:
-  /**
-   * Create a new invalid field.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline field() noexcept;
-
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it. The content is stored in the receiver.
-   *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
-   */
-  template <typename string_type>
-  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Get the key as a raw_json_string. Can be used for direct comparison with
-   * an unescaped C string: e.g., key() == "test". This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key() for a similar function which returns
-   * a more convenient std::string_view result.
-   */
-  simdjson_inline raw_json_string key() const noexcept;
-  /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
-   */
-  simdjson_inline std::string_view key_raw_json_token() const noexcept;
-  /**
-   * Get the key as a string_view. This does not include the quotes and
-   * the string is unprocessed key so it may contain escape characters
-   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
-   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
-   */
-  simdjson_inline std::string_view escaped_key() const noexcept;
-  /**
-   * Get the field value.
-   */
-  simdjson_inline ondemand::value &value() & noexcept;
-  /**
-   * @overload ondemand::value &ondemand::value() & noexcept
-   */
-  simdjson_inline ondemand::value value() && noexcept;
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-protected:
-  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
-  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
-  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
-  friend struct simdjson_result<field>;
-  friend class object_iterator;
-};
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
+}
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
+}
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
+}
 
 } // namespace ondemand
 } // namespace icelake
@@ -72526,338 +71299,340 @@ class field : public std::pair<raw_json_string, value> {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<icelake::ondemand::field> : public icelake::implementation_simdjson_result_base<icelake::ondemand::field> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::field &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(
+  icelake::ondemand::array_iterator &&value
+) noexcept
+  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>(std::forward<icelake::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>({}, error)
+{
+}
 
-  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  template<typename string_type>
-  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> key() noexcept;
-  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> value() noexcept;
-};
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator==(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator!=(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &simdjson_result<icelake::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
+}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-/* end file simdjson/generic/ondemand/field.h for icelake */
-/* including simdjson/generic/ondemand/object.h for icelake: #include "simdjson/generic/ondemand/object.h" */
-/* begin file simdjson/generic/ondemand/object.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
+/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-/**
- * A forward-only JSON object field iterator.
- */
-class object {
-public:
-  /**
-   * Create a new invalid object.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object() noexcept = default;
+simdjson_inline value::value(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
+}
+simdjson_inline value value::start(const value_iterator &iter) noexcept {
+  return iter;
+}
+simdjson_inline value value::resume(const value_iterator &iter) noexcept {
+  return iter;
+}
 
-  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<object_iterator> end() noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a
-   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
+simdjson_inline simdjson_result<array> value::get_array() noexcept {
+  return array::start(iter);
+}
+simdjson_inline simdjson_result<object> value::get_object() noexcept {
+  return object::start(iter);
+}
+simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
+  if (iter.at_start()) {
+    return get_object();
+  } else {
+    return object::resume(iter);
+  }
+}
 
-  /**
-   * Get the value associated with the given JSON pointer. We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
-   * instance: there is no rewind and no invalidation.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
+  return iter.get_raw_json_string();
+}
+simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
+  return iter.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return iter.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
+  return iter.get_wobbly_string();
+}
+simdjson_inline simdjson_result<double> value::get_double() noexcept {
+  return iter.get_double();
+}
+simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
+  return iter.get_double_in_string();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
+  return iter.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
+  return iter.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
+  return iter.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
+  return iter.get_int64_in_string();
+}
+simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
+  return iter.get_bool();
+}
+simdjson_inline simdjson_result<bool> value::is_null() noexcept {
+  return iter.is_null();
+}
 
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
+template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
 
-  /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the object. You should still consume values only once even if you
-   * can iterate through the object more than once. If you unescape a string or a key
-   * within the object more than once, you have unsafe code. Note that rewinding an object
-   * means that you may need to reparse it anew: it is not a free operation.
-   *
-   * @returns true if the object contains some elements (not empty)
-   */
-  inline simdjson_result<bool> reset() & noexcept;
-  /**
-   * This method scans the beginning of the object and checks whether the
-   * object is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   */
-  inline simdjson_result<bool> is_empty() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Consumes the object and returns a string_view instance corresponding to the
-   * object as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-protected:
-  /**
-   * Go to the end of the object, no matter where you are right now.
-   */
-  simdjson_inline error_code consume() noexcept;
-  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
-  static simdjson_inline object resume(const value_iterator &iter) noexcept;
-  simdjson_inline object(const value_iterator &iter) noexcept;
+template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
+template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
 
-  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline value::operator T() noexcept(false) {
+  return get<T>();
+}
+simdjson_inline value::operator array() noexcept(false) {
+  return get_array();
+}
+simdjson_inline value::operator object() noexcept(false) {
+  return get_object();
+}
+simdjson_inline value::operator uint64_t() noexcept(false) {
+  return get_uint64();
+}
+simdjson_inline value::operator int64_t() noexcept(false) {
+  return get_int64();
+}
+simdjson_inline value::operator double() noexcept(false) {
+  return get_double();
+}
+simdjson_inline value::operator std::string_view() noexcept(false) {
+  return get_string(false);
+}
+simdjson_inline value::operator raw_json_string() noexcept(false) {
+  return get_raw_json_string();
+}
+simdjson_inline value::operator bool() noexcept(false) {
+  return get_bool();
+}
+#endif
 
-  value_iterator iter{};
+simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
+  return {};
+}
+simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_array();
+  answer = a.count_elements();
+  // count_elements leaves you pointing inside the array, at the first element.
+  // We need to move back so that the user can create a new array (which requires that
+  // we point at '[').
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
+  simdjson_result<size_t> answer;
+  auto a = get_object();
+  answer = a.count_fields();
+  iter.move_at_start();
+  return answer;
+}
+simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
 
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<object>;
-};
+simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+  return start_or_resume_object().find_field(key);
+}
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
+simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
 
-namespace simdjson {
+simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+  return start_or_resume_object()[key];
+}
 
-template<>
-struct simdjson_result<icelake::ondemand::object> : public icelake::implementation_simdjson_result_base<icelake::ondemand::object> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::object &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+simdjson_inline simdjson_result<json_type> value::type() noexcept {
+  return iter.type();
+}
 
-  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> end() noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> operator[](std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<icelake::ondemand::value> at_path(std::string_view json_path) noexcept;
+simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
 
-  inline simdjson_result<bool> reset() noexcept;
-  inline simdjson_result<bool> is_empty() noexcept;
-  inline simdjson_result<size_t> count_fields() & noexcept;
-  inline simdjson_result<std::string_view> raw_json() noexcept;
+simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
+}
 
-};
 
-} // namespace simdjson
+simdjson_inline bool value::is_negative() noexcept {
+  return iter.is_negative();
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
-/* end file simdjson/generic/ondemand/object.h for icelake */
-/* including simdjson/generic/ondemand/object_iterator.h for icelake: #include "simdjson/generic/ondemand/object_iterator.h" */
-/* begin file simdjson/generic/ondemand/object_iterator.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
+  return iter.is_integer();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
+  return iter.get_number_type();
+}
+simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
+  return iter.get_number();
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
 
-class object_iterator {
-public:
-  /**
-   * Create a new invalid object_iterator.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline object_iterator() noexcept = default;
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
 
-  //
-  // Iterator interface
-  //
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
 
-  // Reads key and value, yielding them to the user.
-  // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline simdjson_result<field> operator*() noexcept;
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const object_iterator &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline object_iterator &operator++() noexcept;
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
 
-private:
-  /**
-   * The underlying JSON iterator.
-   *
-   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
-   * is first used, and never changes afterwards.
-   */
-  value_iterator iter{};
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
+}
 
-  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
-  friend struct simdjson_result<object_iterator>;
-  friend class object;
-};
+simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
+  }
+}
 
 } // namespace ondemand
 } // namespace icelake
@@ -72865,491 +71640,603 @@ class object_iterator {
 
 namespace simdjson {
 
-template<>
-struct simdjson_result<icelake::ondemand::object_iterator> : public icelake::implementation_simdjson_result_base<icelake::ondemand::object_iterator> {
-public:
-  simdjson_inline simdjson_result(icelake::ondemand::object_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
-  // Reads key and value, yielding them to the user.
-  simdjson_inline simdjson_result<icelake::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const simdjson_result<icelake::ondemand::object_iterator> &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const simdjson_result<icelake::ondemand::object_iterator> &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &operator++() noexcept;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-/* end file simdjson/generic/ondemand/object_iterator.h for icelake */
-/* including simdjson/generic/ondemand/serialization.h for icelake: #include "simdjson/generic/ondemand/serialization.h" */
-/* begin file simdjson/generic/ondemand/serialization.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-/**
- * Create a string-view instance out of a document instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept;
-/**
- * Create a string-view instance out of a value instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. The value must
- * not have been accessed previously. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept;
-/**
- * Create a string-view instance out of an object instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept;
-/**
- * Create a string-view instance out of an array instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept;
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x);
-} // namespace simdjson
-
-/**
- * We want to support argument-dependent lookup (ADL).
- * Hence we should define operator<< in the namespace
- * where the argument (here value, object, etc.) resides.
- * Credit: @madhur4127
- * See https://github.com/simdjson/simdjson/issues/1768
- */
-namespace simdjson { namespace icelake { namespace ondemand {
-
-/**
- * Print JSON to an output stream.  It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The element.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x);
-#endif
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The object.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::object> x);
-#endif
-}}} // namespace simdjson::icelake::ondemand
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-/* end file simdjson/generic/ondemand/serialization.h for icelake */
-
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for icelake: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for icelake */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-#include <limits>
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  icelake::ondemand::value &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(
+      std::forward<icelake::ondemand::value>(value)
+    )
+{
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::value>(error)
+{
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
+}
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
+}
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
+  if (error()) { return error(); }
+  return {};
+}
 
-namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
 
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
+}
 
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
 
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
+}
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
+}
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
+}
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
+}
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
+}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
 
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+  if (error()) { return error(); }
+  out = first;
   return SUCCESS;
 }
 
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
+template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
+}
+template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
 
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
+template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+  if (error()) { return error(); }
+  return std::move(first);
+}
 
-  icelake::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
+}
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
+}
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
+}
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+#endif
 
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json_token();
+}
 
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 
-/**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
- *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
- *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
+}
 
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
+simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+  if (error()) { return error(); }
+  return first.current_depth();
+}
 
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
+    std::string_view json_pointer) noexcept {
+  if (error()) {
+      return error();
   }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
+  return first.at_pointer(json_pointer);
 }
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  if (!out) {
-    out.emplace();
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
+      std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
   }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
+  return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for icelake */
-
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for icelake: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for icelake */
+/* including simdjson/generic/ondemand/document-inl.h for icelake: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the array is first found and the iterator is just past the `{`.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
-//   depth == iter->depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter->depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the array iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
-//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
-//
-// ## Terminal State
-//
-// The terminal state has iter->depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
-//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
-//   error == SUCCESS.
-//
-
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
 {
+  logger::log_start_value(iter, "document");
 }
 
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
 }
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
+
+inline void document::rewind() noexcept {
+  iter.rewind();
 }
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
-  bool has_value;
-  SIMDJSON_TRY(iter.started_array().get(has_value));
-  return array(iter);
+
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
 }
 
-simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
+}
+
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
+}
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
+}
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
+}
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
+}
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
+}
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
+    return get_object();
+  } else {
+    return object::resume(resume_value_iterator());
+  }
+}
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
+
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  return array_iterator(iter);
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
-  return array_iterator(iter);
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-simdjson_inline error_code array::consume() noexcept {
-  auto error = iter.json_iter().skip_child(iter.depth()-1);
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
+}
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
+}
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
+}
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
+}
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
+}
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
+}
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
+}
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+}
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
+}
+
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
+  auto a = get_array();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
+  auto a = get_object();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
+  return answer;
+}
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
+  auto a = get_array();
+  return a.at(index);
+}
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
+
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
+  return start_or_resume_object().find_field(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
+  return start_or_resume_object().find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
+  return start_or_resume_object()[key];
+}
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
+  return start_or_resume_object()[key];
+}
+
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
   if(error) { iter.abandon(); }
   return error;
 }
 
-simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
   auto error = consume();
   if(error) { return error; }
   // After 'consume()', we could be left pointing just beyond the document, but that
   // is ok because we are not going to dereference the final pointer position, we just
   // use it to compute the length in bytes.
-  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  const uint8_t * final_point{iter.unsafe_pointer()};
   return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the array after counting the number of elements.
-  iter.reset_array();
-  return count;
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
   if(error) { return error; }
-  return !is_not_empty;
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return (this_type == json_type::string);
 }
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
+}
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
+}
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
+}
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t) {
+  case json_type::array:
+      return (*this).get_array().at_path(json_path);
+  case json_type::object:
+      return (*this).get_object().at_path(json_path);
+  default:
+      return INVALID_JSON_POINTER;
   }
-  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -73358,3224 +72245,2591 @@ simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
-  icelake::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::array>(
-      std::forward<icelake::ondemand::array>(value)
+simdjson_inline simdjson_result<icelake::ondemand::document>::simdjson_result(
+  icelake::ondemand::document &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::document>(
+      std::forward<icelake::ondemand::document>(value)
     )
 {
 }
-simdjson_inline simdjson_result<icelake::ondemand::array>::simdjson_result(
+simdjson_inline simdjson_result<icelake::ondemand::document>::simdjson_result(
   error_code error
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::array>(error)
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::document>(
+      error
+    )
 {
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::begin() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document>::count_elements() & noexcept {
   if (error()) { return error(); }
-  return first.begin();
+  return first.count_elements();
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::array>::end() noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.end();
+  return first.count_fields();
 }
-simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::array>::count_elements() & noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at(size_t index) & noexcept {
   if (error()) { return error(); }
-  return first.count_elements();
+  return first.at(index);
 }
-simdjson_inline  simdjson_result<bool> simdjson_result<icelake::ondemand::array>::is_empty() & noexcept {
+simdjson_inline error_code simdjson_result<icelake::ondemand::document>::rewind() noexcept {
   if (error()) { return error(); }
-  return first.is_empty();
+  first.rewind();
+  return SUCCESS;
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at(size_t index) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.at(index);
+  return first.begin();
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document>::end() & noexcept {
+  return {};
 }
-simdjson_inline  simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array>::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return first.find_field_unordered(key);
 }
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::array>::raw_json() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.find_field_unordered(key);
 }
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for icelake */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(
-  icelake::ondemand::array_iterator &&value
-) noexcept
-  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>(std::forward<icelake::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::document>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : icelake::implementation_simdjson_result_base<icelake::ondemand::array_iterator>({}, error)
-{
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::document>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::array_iterator>::operator*() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
-  return *first;
+  return first.get_uint64();
 }
-simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator==(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-simdjson_inline bool simdjson_result<icelake::ondemand::array_iterator>::operator!=(const simdjson_result<icelake::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> &simdjson_result<icelake::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  icelake::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(
-      std::forward<icelake::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::document>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<icelake::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
+template<typename T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<icelake::ondemand::document>(first).get<T>(out);
+}
 
-template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+template<> simdjson_inline simdjson_result<icelake::ondemand::document> simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<icelake::ondemand::document> simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<icelake::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>(icelake::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>(icelake::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<icelake::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<icelake::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+simdjson_inline bool simdjson_result<icelake::ondemand::document>::at_end() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.at_end();
 }
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+
+simdjson_inline int32_t simdjson_result<icelake::ondemand::document>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for icelake: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for icelake */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-#include <limits>
 
 namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
-
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
-
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
-
-  icelake::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
-}
-
-
+namespace icelake {
+namespace ondemand {
 
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
 /**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
  *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
  *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
-
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
-  }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
-}
-
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
  */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  if (!out) {
-    out.emplace();
-  }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for icelake */
-
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for icelake: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
 template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
 #endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
+
+
 namespace simdjson {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::simdjson_result(icelake::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<icelake::ondemand::document_reference>(std::forward<icelake::ondemand::document_reference>(value), error) {}
 
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  icelake::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(
-      std::forward<icelake::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
+
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document_reference>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document_reference>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::rewind() noexcept {
   if (error()) { return error(); }
-  return {};
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document_reference>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.begin();
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::document_reference>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::document_reference>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document_reference>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document_reference>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document_reference>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document_reference>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document_reference>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document_reference>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::document_reference>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<icelake::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-
-template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
+template <class T>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<icelake::ondemand::document_reference>(first).get<T>(out);
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
+template <>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
+simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::document_reference>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::document_reference>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, icelake::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, icelake::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
   return first.get<T>();
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::document_reference>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
   if (error()) {
-    return error();
+      return error();
   }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value-inl.h for icelake: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for icelake */
+/* including simdjson/generic/ondemand/document_stream-inl.h for icelake: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <algorithm>
+#include <stdexcept>
+
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
+
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
+
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
   }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
 
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
+}
 
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
+}
 
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+#endif  // SIMDJSON_THREADS_ENABLED
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
 #endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
 
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
   }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
+  #endif // SIMDJSON_THREADS_ENABLED
+}
+
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
   }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
+}
+
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
+}
+
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+}
+
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
   }
-  if (escape == json_pointer.size() - 1) {
-    return false;
+}
+
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
+}
+
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
   }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
+
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
   }
-  return true;
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
 }
 
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+}
+
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  icelake::ondemand::value &&value
+simdjson_inline simdjson_result<icelake::ondemand::document_stream>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(
-      std::forward<icelake::ondemand::value>(value)
-    )
+    implementation_simdjson_result_base<icelake::ondemand::document_stream>(error)
 {
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<icelake::ondemand::document_stream>::simdjson_result(
+  icelake::ondemand::document_stream &&value
 ) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::value>(error)
+    implementation_simdjson_result_base<icelake::ondemand::document_stream>(
+      std::forward<icelake::ondemand::document_stream>(value)
+    )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for icelake */
+/* including simdjson/generic/ondemand/field-inl.h for icelake: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
 
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>(icelake::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<icelake::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
 
-template<> simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::get<icelake::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
+
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
   return first;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator icelake::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::field>::simdjson_result(
+  icelake::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::field>(
+      std::forward<icelake::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<icelake::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<icelake::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<icelake::ondemand::field>(error)
+{
 }
-#endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.key();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::value>::raw_json() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.key_raw_json_token();
 }
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::value>::current_location() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.escaped_key();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<icelake::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
+template<typename string_type>
+simdjson_inline error_code simdjson_result<icelake::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for icelake */
-/* including simdjson/generic/ondemand/document-inl.h for icelake: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for icelake */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
 {
-  logger::log_start_value(iter, "document");
+  other.parser = nullptr;
 }
-
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
 
-inline void document::rewind() noexcept {
-  iter.rewind();
-}
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
 
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
 
 
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
-}
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
-}
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
-}
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
-    return get_object();
-  } else {
-    return object::resume(resume_value_iterator());
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
   }
-}
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
 
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
     }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
   }
-}
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
-}
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
-}
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
-}
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
-}
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
-}
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
-}
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
-}
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
+}
 
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
+}
 
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+}
 
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
 #endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
+
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
   }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
+}
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
 
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+}
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
+}
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::document>::simdjson_result(
-  icelake::ondemand::document &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::document>(
-      std::forward<icelake::ondemand::document>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<icelake::ondemand::document>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::document>(
-      error
-    )
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<icelake::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::json_iterator>::simdjson_result(icelake::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::json_iterator>(std::forward<icelake::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/json_type-inl.h for icelake: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+#endif
+
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::document>(first).get<T>();
+
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::document>(first).get<T>(out);
+
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-template<> simdjson_inline simdjson_result<icelake::ondemand::document> simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<icelake::ondemand::document> simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::document>(first);
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>(icelake::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<icelake::ondemand::document>::get<icelake::ondemand::document>(icelake::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<icelake::ondemand::document>(first);
-  return SUCCESS;
+
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_inline bool simdjson_result<icelake::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::json_type>::simdjson_result(icelake::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::json_type>(std::forward<icelake::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for icelake */
+/* including simdjson/generic/ondemand/logger-inl.h for icelake: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <memory>
+#include <cstring>
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+namespace logger {
+
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
+  }
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, icelake::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document>::operator icelake::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
-#endif
 
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline bool simdjson_result<icelake::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-
-simdjson_inline int32_t simdjson_result<icelake::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
-} // namespace simdjson
-
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+}
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
+} // namespace logger
 } // namespace ondemand
 } // namespace icelake
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for icelake */
+/* including simdjson/generic/ondemand/object-inl.h for icelake: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::simdjson_result(icelake::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<icelake::ondemand::document_reference>(std::forward<icelake::ondemand::document_reference>(value), error) {}
+namespace icelake {
+namespace ondemand {
 
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
 
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<icelake::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<icelake::ondemand::array_iterator> simdjson_result<icelake::ondemand::document_reference>::end() & noexcept {
-  return {};
+
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
-simdjson_inline simdjson_result<icelake::ondemand::array> simdjson_result<icelake::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
-simdjson_inline simdjson_result<icelake::ondemand::object> simdjson_result<icelake::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document_reference>::get_uint64() noexcept {
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::object>::simdjson_result(icelake::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::object>(std::forward<icelake::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator> simdjson_result<icelake::ondemand::object>::begin() noexcept {
   if (error()) { return error(); }
-  return first.get_uint64();
+  return first.begin();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<icelake::ondemand::document_reference>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator> simdjson_result<icelake::ondemand::object>::end() noexcept {
   if (error()) { return error(); }
-  return first.get_uint64_in_string();
+  return first.end();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document_reference>::get_int64() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.get_int64();
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<icelake::ondemand::document_reference>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_int64_in_string();
+  return std::forward<icelake::ondemand::object>(first).find_field_unordered(key);
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document_reference>::get_double() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.get_double();
+  return first[key];
 }
-simdjson_inline simdjson_result<double> simdjson_result<icelake::ondemand::document_reference>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::operator[](std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_double_in_string();
+  return std::forward<icelake::ondemand::object>(first)[key];
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+  return first.find_field(key);
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+  return std::forward<icelake::ondemand::object>(first).find_field(key);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::get_wobbly_string() noexcept {
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.get_wobbly_string();
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::get_bool() noexcept {
+
+inline simdjson_result<bool> simdjson_result<icelake::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return first.get_bool();
+  return first.reset();
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::get_value() noexcept {
+
+inline simdjson_result<bool> simdjson_result<icelake::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.get_value();
+  return first.is_empty();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_null() noexcept {
+
+simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.count_fields();
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() & noexcept {
+
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::object>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  return first.raw_json();
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<icelake::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::document_reference>(first).get<T>();
-}
-template <class T>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-template <class T>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::document_reference>(first).get<T>(out);
-}
-simdjson_inline simdjson_result<icelake::ondemand::json_type> simdjson_result<icelake::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-template <>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-template <>
-simdjson_inline error_code simdjson_result<icelake::ondemand::document_reference>::get(icelake::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<icelake::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<icelake::number_type> simdjson_result<icelake::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<icelake::ondemand::number> simdjson_result<icelake::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, icelake::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, icelake::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for icelake */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+//
+// object_iterator
+//
+
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
 }
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
+
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+SIMDJSON_POP_DISABLE_WARNINGS
+
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
+
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
+  icelake::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
+{
+  first.iter.assert_is_valid();
 }
-simdjson_inline simdjson_result<icelake::ondemand::document_reference>::operator icelake::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
+{
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::document_reference>::current_location() noexcept {
+simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return *first;
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
+// Checks for ']' and ','
+simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for icelake */
-/* including simdjson/generic/ondemand/document_stream-inl.h for icelake: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
+}
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-#endif
-}
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
-}
+  json.remove_utf8_bom();
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
-}
-
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
   }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
-
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
-
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
   }
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
 
 } // namespace ondemand
 } // namespace icelake
@@ -76583,1585 +74837,1636 @@ inline void document_stream::start_stage1_thread() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::document_stream>(error)
-{
-}
-simdjson_inline simdjson_result<icelake::ondemand::document_stream>::simdjson_result(
-  icelake::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::document_stream>(
-      std::forward<icelake::ondemand::document_stream>(value)
-    )
-{
-}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
 
-}
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for icelake */
-/* including simdjson/generic/ondemand/field-inl.h for icelake: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for icelake */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for icelake: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace icelake {
 namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
-}
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::field>::simdjson_result(
-  icelake::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::field>(
-      std::forward<icelake::ondemand::field>(value)
-    )
-{
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<icelake::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<icelake::ondemand::field>(error)
-{
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::raw_json_string> simdjson_result<icelake::ondemand::field>::key() noexcept {
-  if (error()) { return error(); }
-  return first.key();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::key_raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.key_raw_json_token();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::escaped_key() noexcept {
-  if (error()) { return error(); }
-  return first.escaped_key();
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<icelake::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(icelake::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(std::forward<icelake::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<icelake::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.raw();
 }
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<icelake::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.unescape(iter, allow_replacement);
 }
-
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<icelake::ondemand::raw_json_string>::unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.unescape_wobbly(iter);
 }
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for icelake */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for icelake */
+/* including simdjson/generic/ondemand/serialization-inl.h for icelake: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-namespace icelake {
-namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
-}
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
-}
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace icelake::ondemand;
+  icelake::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
     {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
+      icelake::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
     }
-  }
-  return count == 0;
-}
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
+    case json_type::object:
+    {
+      icelake::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
     }
+    default:
+      return trim(x.raw_json_token());
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+inline simdjson_result<std::string_view> to_json_string(icelake::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<icelake::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
+namespace simdjson { namespace icelake { namespace ondemand {
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
   }
-  return reinterpret_cast<const char *>(token.peek());
 }
+#endif
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::icelake::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::icelake::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::icelake::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
+}}} // namespace simdjson::icelake::ondemand
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for icelake */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace icelake {
+namespace ondemand {
+
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
+}
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
 }
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
+} // namespace ondemand
+} // namespace icelake
+} // namespace simdjson
 
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
+namespace simdjson {
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
-}
+simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(icelake::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(std::forward<icelake::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::token_iterator>(error) {}
 
-#endif
+} // namespace simdjson
 
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
-}
-
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
-}
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::json_iterator>::simdjson_result(icelake::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::json_iterator>(std::forward<icelake::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::json_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/json_type-inl.h for icelake: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace icelake {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
-
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
 }
-#endif
 
-
-
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
 }
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
-}
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
   }
-  if(is_int64()) {
-    return double(payload.signed_integer);
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
   }
-  return double(payload.unsigned_integer);
-}
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
 
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
-}
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
-}
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
-}
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-namespace simdjson {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
 
-simdjson_inline simdjson_result<icelake::ondemand::json_type>::simdjson_result(icelake::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::json_type>(std::forward<icelake::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::json_type>(error) {}
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-} // namespace simdjson
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for icelake */
-/* including simdjson/generic/ondemand/logger-inl.h for icelake: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-#include <memory>
-#include <cstring>
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-namespace logger {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
 
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
   }
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
+
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
-}
-
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
-}
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
+  }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  return true;
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    }
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
 }
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
+  }
 }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
 }
-
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
 }
-
-} // namespace logger
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for icelake */
-/* including simdjson/generic/ondemand/object-inl.h for icelake: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  return value(iter.child());
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
 }
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
 }
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
 }
-
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
 }
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
 }
-
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
 }
-
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
 }
-
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
+  if(error) { return error; }
+  return num;
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
   }
-  return child;
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
+simdjson_inline simdjson_result<icelake::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
   }
-  return at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
 }
-
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
   if(error) { return error; }
-  return !is_not_empty;
-}
-
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
-}
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::object>::simdjson_result(icelake::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::object>(std::forward<icelake::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator> simdjson_result<icelake::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator> simdjson_result<icelake::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::object>(first).find_field_unordered(key);
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::object>(first)[key];
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<icelake::ondemand::object>(first).find_field(key);
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-simdjson_inline simdjson_result<icelake::ondemand::value> simdjson_result<icelake::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
   }
-  return first.at_path(json_path);
+  return result;
 }
-
-inline simdjson_result<bool> simdjson_result<icelake::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
 }
 
-inline simdjson_result<bool> simdjson_result<icelake::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
 }
-
-simdjson_inline  simdjson_result<size_t> simdjson_result<icelake::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
 }
-
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<icelake::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
 }
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for icelake */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
-
-//
-// object_iterator
-//
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
+  return _json_iter->skip_child(depth());
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
 }
 
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
 SIMDJSON_PUSH_DISABLE_WARNINGS
 SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
 }
 SIMDJSON_POP_DISABLE_WARNINGS
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
+}
 
-namespace simdjson {
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
+}
 
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(
-  icelake::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>(std::forward<icelake::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
 }
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<icelake::ondemand::object_iterator>({}, error)
-{
+
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
 }
 
-simdjson_inline simdjson_result<icelake::ondemand::field> simdjson_result<icelake::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator==(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<icelake::ondemand::object_iterator>::operator!=(const simdjson_result<icelake::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<icelake::ondemand::object_iterator> &simdjson_result<icelake::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
+}
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
 }
 
-} // namespace simdjson
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/parser-inl.h for icelake: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
+}
 
-namespace simdjson {
-namespace icelake {
-namespace ondemand {
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
   } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
   }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
+
+
   return SUCCESS;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+  assert_at_root();
+  return _json_iter->peek();
 }
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+  assert_at_non_root_start();
+  return _json_iter->peek();
+}
 
-  json.remove_utf8_bom();
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
+  }
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
+}
+
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
 }
 
 } // namespace ondemand
@@ -78170,2608 +76475,2221 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(icelake::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(std::forward<icelake::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<icelake::ondemand::value_iterator>::simdjson_result(icelake::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::value_iterator>(std::forward<icelake::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<icelake::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<icelake::ondemand::value_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for icelake */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for icelake: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
 
+
+/* end file simdjson/generic/ondemand/amalgamated.h for icelake */
+/* including simdjson/icelake/end.h: #include "simdjson/icelake/end.h" */
+/* begin file simdjson/icelake/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
+#if !SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
+SIMDJSON_UNTARGET_REGION
+#endif
 
-namespace icelake {
-namespace ondemand {
+/* undefining SIMDJSON_IMPLEMENTATION from "icelake" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/icelake/end.h */
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
+#endif // SIMDJSON_ICELAKE_ONDEMAND_H
+/* end file simdjson/icelake/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
+/* including simdjson/ppc64/ondemand.h: #include "simdjson/ppc64/ondemand.h" */
+/* begin file simdjson/ppc64/ondemand.h */
+#ifndef SIMDJSON_PPC64_ONDEMAND_H
+#define SIMDJSON_PPC64_ONDEMAND_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
+/* including simdjson/ppc64/begin.h: #include "simdjson/ppc64/begin.h" */
+/* begin file simdjson/ppc64/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "ppc64" */
+#define SIMDJSON_IMPLEMENTATION ppc64
+/* including simdjson/ppc64/base.h: #include "simdjson/ppc64/base.h" */
+/* begin file simdjson/ppc64/base.h */
+#ifndef SIMDJSON_PPC64_BASE_H
+#define SIMDJSON_PPC64_BASE_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
-}
+namespace simdjson {
+/**
+ * Implementation for ALTIVEC (PPC64).
+ */
+namespace ppc64 {
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
-}
+class implementation;
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
-}
+namespace {
+namespace simd {
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
+} // namespace simd
+} // unnamed namespace
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
-}
+} // namespace ppc64
+} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+#endif // SIMDJSON_PPC64_BASE_H
+/* end file simdjson/ppc64/base.h */
+/* including simdjson/ppc64/intrinsics.h: #include "simdjson/ppc64/intrinsics.h" */
+/* begin file simdjson/ppc64/intrinsics.h */
+#ifndef SIMDJSON_PPC64_INTRINSICS_H
+#define SIMDJSON_PPC64_INTRINSICS_H
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+// This should be the correct header whether
+// you use visual studio or other compilers.
+#include <altivec.h>
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+// These are defined by altivec.h in GCC toolchain, it is safe to undef them.
+#ifdef bool
+#undef bool
 #endif
-    return false;
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#ifdef vector
+#undef vector
 #endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
+static_assert(sizeof(__vector unsigned char) <= simdjson::SIMDJSON_PADDING, "insufficient padding for ppc64");
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+#endif //  SIMDJSON_PPC64_INTRINSICS_H
+/* end file simdjson/ppc64/intrinsics.h */
+/* including simdjson/ppc64/bitmanipulation.h: #include "simdjson/ppc64/bitmanipulation.h" */
+/* begin file simdjson/ppc64/bitmanipulation.h */
+#ifndef SIMDJSON_PPC64_BITMANIPULATION_H
+#define SIMDJSON_PPC64_BITMANIPULATION_H
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+namespace simdjson {
+namespace ppc64 {
+namespace {
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long ret;
+  // Search the mask data from least significant bit (LSB)
+  // to the most significant bit (MSB) for a set bit (1).
+  _BitScanForward64(&ret, input_num);
+  return (int)ret;
+#else  // SIMDJSON_REGULAR_VISUAL_STUDIO
+  return __builtin_ctzll(input_num);
+#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
+}
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num - 1);
+}
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  unsigned long leading_zero = 0;
+  // Search the mask data from most significant bit (MSB)
+  // to least significant bit (LSB) for a set bit (1).
+  if (_BitScanReverse64(&leading_zero, input_num))
+    return (int)(63 - leading_zero);
+  else
+    return 64;
+#else
+  return __builtin_clzll(input_num);
+#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
+}
+
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+simdjson_inline int count_ones(uint64_t input_num) {
+  // note: we do not support legacy 32-bit Windows in this kernel
+  return __popcnt64(input_num); // Visual Studio wants two underscores
+}
+#else
+simdjson_inline int count_ones(uint64_t input_num) {
+  return __builtin_popcountll(input_num);
+}
 #endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
+                                         uint64_t *result) {
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+  *result = value1 + value2;
+  return *result < value1;
+#else
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
 #endif
-  }
+}
 
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+} // unnamed namespace
+} // namespace ppc64
+} // namespace simdjson
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
+#endif // SIMDJSON_PPC64_BITMANIPULATION_H
+/* end file simdjson/ppc64/bitmanipulation.h */
+/* including simdjson/ppc64/bitmask.h: #include "simdjson/ppc64/bitmask.h" */
+/* begin file simdjson/ppc64/bitmask.h */
+#ifndef SIMDJSON_PPC64_BITMASK_H
+#define SIMDJSON_PPC64_BITMASK_H
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
+namespace simdjson {
+namespace ppc64 {
+namespace {
 
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is
+// encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
+  // You can use the version below, however gcc sometimes miscompiles
+  // vec_pmsum_be, it happens somewhere around between 8 and 9th version.
+  // The performance boost was not noticeable, falling back to a usual
+  // implementation.
+  //   __vector unsigned long long all_ones = {~0ull, ~0ull};
+  //   __vector unsigned long long mask = {bitmask, 0};
+  //   // Clang and GCC return different values for pmsum for ull so cast it to one.
+  //   // Generally it is not specified by ALTIVEC ISA what is returned by
+  //   // vec_pmsum_be.
+  // #if defined(__LITTLE_ENDIAN__)
+  //   return (uint64_t)(((__vector unsigned long long)vec_pmsum_be(all_ones, mask))[0]);
+  // #else
+  //   return (uint64_t)(((__vector unsigned long long)vec_pmsum_be(all_ones, mask))[1]);
+  // #endif
+  bitmask ^= bitmask << 1;
+  bitmask ^= bitmask << 2;
+  bitmask ^= bitmask << 4;
+  bitmask ^= bitmask << 8;
+  bitmask ^= bitmask << 16;
+  bitmask ^= bitmask << 32;
+  return bitmask;
+}
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
+} // unnamed namespace
+} // namespace ppc64
+} // namespace simdjson
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+#endif
+/* end file simdjson/ppc64/bitmask.h */
+/* including simdjson/ppc64/numberparsing_defs.h: #include "simdjson/ppc64/numberparsing_defs.h" */
+/* begin file simdjson/ppc64/numberparsing_defs.h */
+#ifndef SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+#define SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
+#include <cstring>
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
+#if defined(__linux__)
+#include <byteswap.h>
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#endif
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
+namespace simdjson {
+namespace ppc64 {
+namespace numberparsing {
 
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
+// we don't have appropriate instructions, so let us use a scalar function
+// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+/** @private */
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  uint64_t val;
+  std::memcpy(&val, chars, sizeof(uint64_t));
+#ifdef __BIG_ENDIAN__
+#if defined(__linux__)
+  val = bswap_64(val);
+#elif defined(__FreeBSD__)
+  val = bswap64(val);
+#endif
+#endif
+  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
+  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
+/** @private */
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+#if SIMDJSON_IS_ARM64
+  // ARM64 has native support for 64-bit multiplications, no need to emultate
+  answer.high = __umulh(value1, value2);
+  answer.low = value1 * value2;
+#else
+  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
+#endif // SIMDJSON_IS_ARM64
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
+#endif
+  return answer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
-}
+} // namespace numberparsing
+} // namespace ppc64
+} // namespace simdjson
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
-  return answer;
-}
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
+#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
+#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+/* end file simdjson/ppc64/numberparsing_defs.h */
+/* including simdjson/ppc64/simd.h: #include "simdjson/ppc64/simd.h" */
+/* begin file simdjson/ppc64/simd.h */
+#ifndef SIMDJSON_PPC64_SIMD_H
+#define SIMDJSON_PPC64_SIMD_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <type_traits>
+
+namespace simdjson {
+namespace ppc64 {
+namespace {
+namespace simd {
+
+using __m128i = __vector unsigned char;
+
+template <typename Child> struct base {
+  __m128i value;
+
+  // Zero constructor
+  simdjson_inline base() : value{__m128i()} {}
+
+  // Conversion from SIMD register
+  simdjson_inline base(const __m128i _value) : value(_value) {}
+
+  // Conversion to SIMD register
+  simdjson_inline operator const __m128i &() const {
+    return this->value;
   }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  return true;
-}
+  simdjson_inline operator __m128i &() { return this->value; }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
-    }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
+  // Bit operations
+  simdjson_inline Child operator|(const Child other) const {
+    return vec_or(this->value, (__m128i)other);
   }
-  return SUCCESS;
-}
+  simdjson_inline Child operator&(const Child other) const {
+    return vec_and(this->value, (__m128i)other);
+  }
+  simdjson_inline Child operator^(const Child other) const {
+    return vec_xor(this->value, (__m128i)other);
+  }
+  simdjson_inline Child bit_andnot(const Child other) const {
+    return vec_andc(this->value, (__m128i)other);
+  }
+  simdjson_inline Child &operator|=(const Child other) {
+    auto this_cast = static_cast<Child*>(this);
+    *this_cast = *this_cast | other;
+    return *this_cast;
+  }
+  simdjson_inline Child &operator&=(const Child other) {
+    auto this_cast = static_cast<Child*>(this);
+    *this_cast = *this_cast & other;
+    return *this_cast;
+  }
+  simdjson_inline Child &operator^=(const Child other) {
+    auto this_cast = static_cast<Child*>(this);
+    *this_cast = *this_cast ^ other;
+    return *this_cast;
+  }
+};
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
+template <typename T, typename Mask = simd8<bool>>
+struct base8 : base<simd8<T>> {
+  typedef uint16_t bitmask_t;
+  typedef uint32_t bitmask2_t;
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
+  simdjson_inline base8() : base<simd8<T>>() {}
+  simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
 
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
+  friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) {
+    return (__m128i)vec_cmpeq(lhs.value, (__m128i)rhs);
   }
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+  static const int SIZE = sizeof(base<simd8<T>>::value);
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
-}
-
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+  template <int N = 1>
+  simdjson_inline simd8<T> prev(simd8<T> prev_chunk) const {
+    __m128i chunk = this->value;
+#ifdef __LITTLE_ENDIAN__
+    chunk = (__m128i)vec_reve(this->value);
+    prev_chunk = (__m128i)vec_reve((__m128i)prev_chunk);
+#endif
+    chunk = (__m128i)vec_sld((__m128i)prev_chunk, (__m128i)chunk, 16 - N);
+#ifdef __LITTLE_ENDIAN__
+    chunk = (__m128i)vec_reve((__m128i)chunk);
+#endif
+    return chunk;
   }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
+};
 
-simdjson_inline simdjson_result<icelake::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
+// SIMD byte mask type (returned by things like eq and gt)
+template <> struct simd8<bool> : base8<bool> {
+  static simdjson_inline simd8<bool> splat(bool _value) {
+    return (__m128i)vec_splats((unsigned char)(-(!!_value)));
   }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
+
+  simdjson_inline simd8() : base8<bool>() {}
+  simdjson_inline simd8(const __m128i _value)
+      : base8<bool>(_value) {}
+  // Splat constructor
+  simdjson_inline simd8(bool _value)
+      : base8<bool>(splat(_value)) {}
+
+  simdjson_inline int to_bitmask() const {
+    __vector unsigned long long result;
+    const __m128i perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40,
+                               0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00};
+
+    result = ((__vector unsigned long long)vec_vbpermq((__m128i)this->value,
+                                                       (__m128i)perm_mask));
+#ifdef __LITTLE_ENDIAN__
+    return static_cast<int>(result[1]);
+#else
+    return static_cast<int>(result[0]);
+#endif
   }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
+  simdjson_inline bool any() const {
+    return !vec_all_eq(this->value, (__m128i)vec_splats(0));
   }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
+  simdjson_inline simd8<bool> operator~() const {
+    return this->value ^ (__m128i)splat(true);
   }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
+};
+
+template <typename T> struct base8_numeric : base8<T> {
+  static simdjson_inline simd8<T> splat(T value) {
+    (void)value;
+    return (__m128i)vec_splats(value);
   }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
+  static simdjson_inline simd8<T> zero() { return splat(0); }
+  static simdjson_inline simd8<T> load(const T values[16]) {
+    return (__m128i)(vec_vsx_ld(0, reinterpret_cast<const uint8_t *>(values)));
   }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
+  // Repeat 16 values as many times as necessary (usually for lookup tables)
+  static simdjson_inline simd8<T> repeat_16(T v0, T v1, T v2, T v3, T v4,
+                                                   T v5, T v6, T v7, T v8, T v9,
+                                                   T v10, T v11, T v12, T v13,
+                                                   T v14, T v15) {
+    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+                    v14, v15);
   }
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+  simdjson_inline base8_numeric() : base8<T>() {}
+  simdjson_inline base8_numeric(const __m128i _value)
+      : base8<T>(_value) {}
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
+  // Store to array
+  simdjson_inline void store(T dst[16]) const {
+    vec_vsx_st(this->value, 0, reinterpret_cast<__m128i *>(dst));
   }
-  return result;
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
+  // Override to distinguish from bool version
+  simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+
+  // Addition/subtraction are the same for signed and unsigned
+  simdjson_inline simd8<T> operator+(const simd8<T> other) const {
+    return (__m128i)((__m128i)this->value + (__m128i)other);
   }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
+  simdjson_inline simd8<T> operator-(const simd8<T> other) const {
+    return (__m128i)((__m128i)this->value - (__m128i)other);
   }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
+  simdjson_inline simd8<T> &operator+=(const simd8<T> other) {
+    *this = *this + other;
+    return *static_cast<simd8<T> *>(this);
   }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
+  simdjson_inline simd8<T> &operator-=(const simd8<T> other) {
+    *this = *this - other;
+    return *static_cast<simd8<T> *>(this);
   }
-  return result;
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
-
-  return _json_iter->skip_child(depth());
-}
-
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
-}
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+  // Perform a lookup assuming the value is between 0 and 16 (undefined behavior
+  // for out of range values)
+  template <typename L>
+  simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+    return (__m128i)vec_perm((__m128i)lookup_table, (__m128i)lookup_table, this->value);
+  }
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
-}
+  // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted
+  // as a bitset). Passing a 0 value for mask would be equivalent to writing out
+  // every byte to output. Only the first 16 - count_ones(mask) bytes of the
+  // result are significant but 16 bytes get written. Design consideration: it
+  // seems like a function with the signature simd8<L> compress(uint32_t mask)
+  // would be sensible, but the AVX ISA makes this kind of approach difficult.
+  template <typename L>
+  simdjson_inline void compress(uint16_t mask, L *output) const {
+    using internal::BitsSetTable256mul2;
+    using internal::pshufb_combine_table;
+    using internal::thintable_epi8;
+    // this particular implementation was inspired by work done by @animetosho
+    // we do it in two steps, first 8 bytes and then second 8 bytes
+    uint8_t mask1 = uint8_t(mask);      // least significant 8 bits
+    uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
+    // next line just loads the 64-bit values thintable_epi8[mask1] and
+    // thintable_epi8[mask2] into a 128-bit register, using only
+    // two instructions on most compilers.
+#ifdef __LITTLE_ENDIAN__
+    __m128i shufmask = (__m128i)(__vector unsigned long long){
+        thintable_epi8[mask1], thintable_epi8[mask2]};
+#else
+    __m128i shufmask = (__m128i)(__vector unsigned long long){
+        thintable_epi8[mask2], thintable_epi8[mask1]};
+    shufmask = (__m128i)vec_reve((__m128i)shufmask);
+#endif
+    // we increment by 0x08 the second half of the mask
+    shufmask = ((__m128i)shufmask) +
+               ((__m128i)(__vector int){0, 0, 0x08080808, 0x08080808});
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
-}
+    // this is the version "nearly pruned"
+    __m128i pruned = vec_perm(this->value, this->value, shufmask);
+    // we still need to put the two halves together.
+    // we compute the popcount of the first half:
+    int pop1 = BitsSetTable256mul2[mask1];
+    // then load the corresponding mask, what it does is to write
+    // only the first pop1 bytes from the first 8 bytes, and then
+    // it fills in with the bytes from the second 8 bytes + some filling
+    // at the end.
+    __m128i compactmask =
+        vec_vsx_ld(0, reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
+    __m128i answer = vec_perm(pruned, (__m128i)vec_splats(0), compactmask);
+    vec_vsx_st(answer, 0, reinterpret_cast<__m128i *>(output));
+  }
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
-}
+  template <typename L>
+  simdjson_inline simd8<L>
+  lookup_16(L replace0, L replace1, L replace2, L replace3, L replace4,
+            L replace5, L replace6, L replace7, L replace8, L replace9,
+            L replace10, L replace11, L replace12, L replace13, L replace14,
+            L replace15) const {
+    return lookup_16(simd8<L>::repeat_16(
+        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
+        replace7, replace8, replace9, replace10, replace11, replace12,
+        replace13, replace14, replace15));
+  }
+};
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
-}
+// Signed bytes
+template <> struct simd8<int8_t> : base8_numeric<int8_t> {
+  simdjson_inline simd8() : base8_numeric<int8_t>() {}
+  simdjson_inline simd8(const __m128i _value)
+      : base8_numeric<int8_t>(_value) {}
+  // Splat constructor
+  simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+  // Array constructor
+  simdjson_inline simd8(const int8_t *values) : simd8(load(values)) {}
+  // Member-by-member initialization
+  simdjson_inline simd8(int8_t v0, int8_t v1, int8_t v2, int8_t v3,
+                               int8_t v4, int8_t v5, int8_t v6, int8_t v7,
+                               int8_t v8, int8_t v9, int8_t v10, int8_t v11,
+                               int8_t v12, int8_t v13, int8_t v14, int8_t v15)
+      : simd8((__m128i)(__vector signed char){v0, v1, v2, v3, v4, v5, v6, v7,
+                                              v8, v9, v10, v11, v12, v13, v14,
+                                              v15}) {}
+  // Repeat 16 values as many times as necessary (usually for lookup tables)
+  simdjson_inline static simd8<int8_t>
+  repeat_16(int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5,
+            int8_t v6, int8_t v7, int8_t v8, int8_t v9, int8_t v10, int8_t v11,
+            int8_t v12, int8_t v13, int8_t v14, int8_t v15) {
+    return simd8<int8_t>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+                         v13, v14, v15);
+  }
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
-}
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
-}
+  // Order-sensitive comparisons
+  simdjson_inline simd8<int8_t>
+  max_val(const simd8<int8_t> other) const {
+    return (__m128i)vec_max((__vector signed char)this->value,
+                            (__vector signed char)(__m128i)other);
+  }
+  simdjson_inline simd8<int8_t>
+  min_val(const simd8<int8_t> other) const {
+    return (__m128i)vec_min((__vector signed char)this->value,
+                            (__vector signed char)(__m128i)other);
+  }
+  simdjson_inline simd8<bool>
+  operator>(const simd8<int8_t> other) const {
+    return (__m128i)vec_cmpgt((__vector signed char)this->value,
+                              (__vector signed char)(__m128i)other);
+  }
+  simdjson_inline simd8<bool>
+  operator<(const simd8<int8_t> other) const {
+    return (__m128i)vec_cmplt((__vector signed char)this->value,
+                              (__vector signed char)(__m128i)other);
+  }
+};
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+// Unsigned bytes
+template <> struct simd8<uint8_t> : base8_numeric<uint8_t> {
+  simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+  simdjson_inline simd8(const __m128i _value)
+      : base8_numeric<uint8_t>(_value) {}
+  // Splat constructor
+  simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+  // Array constructor
+  simdjson_inline simd8(const uint8_t *values) : simd8(load(values)) {}
+  // Member-by-member initialization
+  simdjson_inline
+  simd8(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5,
+        uint8_t v6, uint8_t v7, uint8_t v8, uint8_t v9, uint8_t v10,
+        uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15)
+      : simd8((__m128i){v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+                        v13, v14, v15}) {}
+  // Repeat 16 values as many times as necessary (usually for lookup tables)
+  simdjson_inline static simd8<uint8_t>
+  repeat_16(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4,
+            uint8_t v5, uint8_t v6, uint8_t v7, uint8_t v8, uint8_t v9,
+            uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14,
+            uint8_t v15) {
+    return simd8<uint8_t>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+                          v13, v14, v15);
+  }
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
+  // Saturated math
+  simdjson_inline simd8<uint8_t>
+  saturating_add(const simd8<uint8_t> other) const {
+    return (__m128i)vec_adds(this->value, (__m128i)other);
+  }
+  simdjson_inline simd8<uint8_t>
+  saturating_sub(const simd8<uint8_t> other) const {
+    return (__m128i)vec_subs(this->value, (__m128i)other);
+  }
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
-}
-
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
-
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
+  // Order-specific operations
+  simdjson_inline simd8<uint8_t>
+  max_val(const simd8<uint8_t> other) const {
+    return (__m128i)vec_max(this->value, (__m128i)other);
+  }
+  simdjson_inline simd8<uint8_t>
+  min_val(const simd8<uint8_t> other) const {
+    return (__m128i)vec_min(this->value, (__m128i)other);
+  }
+  // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+  simdjson_inline simd8<uint8_t>
+  gt_bits(const simd8<uint8_t> other) const {
+    return this->saturating_sub(other);
+  }
+  // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+  simdjson_inline simd8<uint8_t>
+  lt_bits(const simd8<uint8_t> other) const {
+    return other.saturating_sub(*this);
+  }
+  simdjson_inline simd8<bool>
+  operator<=(const simd8<uint8_t> other) const {
+    return other.max_val(*this) == other;
+  }
+  simdjson_inline simd8<bool>
+  operator>=(const simd8<uint8_t> other) const {
+    return other.min_val(*this) == other;
+  }
+  simdjson_inline simd8<bool>
+  operator>(const simd8<uint8_t> other) const {
+    return this->gt_bits(other).any_bits_set();
+  }
+  simdjson_inline simd8<bool>
+  operator<(const simd8<uint8_t> other) const {
+    return this->gt_bits(other).any_bits_set();
   }
 
+  // Bit-specific operations
+  simdjson_inline simd8<bool> bits_not_set() const {
+    return (__m128i)vec_cmpeq(this->value, (__m128i)vec_splats(uint8_t(0)));
+  }
+  simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const {
+    return (*this & bits).bits_not_set();
+  }
+  simdjson_inline simd8<bool> any_bits_set() const {
+    return ~this->bits_not_set();
+  }
+  simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const {
+    return ~this->bits_not_set(bits);
+  }
+  simdjson_inline bool bits_not_set_anywhere() const {
+    return vec_all_eq(this->value, (__m128i)vec_splats(0));
+  }
+  simdjson_inline bool any_bits_set_anywhere() const {
+    return !bits_not_set_anywhere();
+  }
+  simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
+    return vec_all_eq(vec_and(this->value, (__m128i)bits),
+                      (__m128i)vec_splats(0));
+  }
+  simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const {
+    return !bits_not_set_anywhere(bits);
+  }
+  template <int N> simdjson_inline simd8<uint8_t> shr() const {
+    return simd8<uint8_t>(
+        (__m128i)vec_sr(this->value, (__m128i)vec_splat_u8(N)));
+  }
+  template <int N> simdjson_inline simd8<uint8_t> shl() const {
+    return simd8<uint8_t>(
+        (__m128i)vec_sl(this->value, (__m128i)vec_splat_u8(N)));
+  }
+};
 
-  return SUCCESS;
-}
-
-
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
-
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
-
-  assert_at_non_root_start();
-  return _json_iter->peek();
-}
-
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
-}
+template <typename T> struct simd8x64 {
+  static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+  static_assert(NUM_CHUNKS == 4,
+                "PPC64 kernel should use four registers per 64-byte block.");
+  const simd8<T> chunks[NUM_CHUNKS];
 
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
-}
+  simd8x64(const simd8x64<T> &o) = delete; // no copy allowed
+  simd8x64<T> &
+  operator=(const simd8<T>& other) = delete; // no assignment allowed
+  simd8x64() = delete;                      // no default constructor allowed
 
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
-}
+  simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1,
+                                  const simd8<T> chunk2, const simd8<T> chunk3)
+      : chunks{chunk0, chunk1, chunk2, chunk3} {}
+  simdjson_inline simd8x64(const T ptr[64])
+      : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr + 16),
+               simd8<T>::load(ptr + 32), simd8<T>::load(ptr + 48)} {}
 
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
-}
+  simdjson_inline void store(T ptr[64]) const {
+    this->chunks[0].store(ptr + sizeof(simd8<T>) * 0);
+    this->chunks[1].store(ptr + sizeof(simd8<T>) * 1);
+    this->chunks[2].store(ptr + sizeof(simd8<T>) * 2);
+    this->chunks[3].store(ptr + sizeof(simd8<T>) * 3);
+  }
 
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+  simdjson_inline simd8<T> reduce_or() const {
+    return (this->chunks[0] | this->chunks[1]) |
+           (this->chunks[2] | this->chunks[3]);
+  }
 
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+  simdjson_inline uint64_t compress(uint64_t mask, T *output) const {
+    this->chunks[0].compress(uint16_t(mask), output);
+    this->chunks[1].compress(uint16_t(mask >> 16),
+                             output + 16 - count_ones(mask & 0xFFFF));
+    this->chunks[2].compress(uint16_t(mask >> 32),
+                             output + 32 - count_ones(mask & 0xFFFFFFFF));
+    this->chunks[3].compress(uint16_t(mask >> 48),
+                             output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
+    return 64 - count_ones(mask);
+  }
 
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+  simdjson_inline uint64_t to_bitmask() const {
+    uint64_t r0 = uint32_t(this->chunks[0].to_bitmask());
+    uint64_t r1 = this->chunks[1].to_bitmask();
+    uint64_t r2 = this->chunks[2].to_bitmask();
+    uint64_t r3 = this->chunks[3].to_bitmask();
+    return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
+  }
 
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
-}
+  simdjson_inline uint64_t eq(const T m) const {
+    const simd8<T> mask = simd8<T>::splat(m);
+    return simd8x64<bool>(this->chunks[0] == mask, this->chunks[1] == mask,
+                          this->chunks[2] == mask, this->chunks[3] == mask)
+        .to_bitmask();
+  }
 
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
-}
+  simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+    return simd8x64<bool>(this->chunks[0] == other.chunks[0],
+                          this->chunks[1] == other.chunks[1],
+                          this->chunks[2] == other.chunks[2],
+                          this->chunks[3] == other.chunks[3])
+        .to_bitmask();
+  }
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
-}
+  simdjson_inline uint64_t lteq(const T m) const {
+    const simd8<T> mask = simd8<T>::splat(m);
+    return simd8x64<bool>(this->chunks[0] <= mask, this->chunks[1] <= mask,
+                          this->chunks[2] <= mask, this->chunks[3] <= mask)
+        .to_bitmask();
+  }
+}; // struct simd8x64<T>
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
-}
+} // namespace simd
+} // unnamed namespace
+} // namespace ppc64
+} // namespace simdjson
 
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+#endif // SIMDJSON_PPC64_SIMD_INPUT_H
+/* end file simdjson/ppc64/simd.h */
+/* including simdjson/ppc64/stringparsing_defs.h: #include "simdjson/ppc64/stringparsing_defs.h" */
+/* begin file simdjson/ppc64/stringparsing_defs.h */
+#ifndef SIMDJSON_PPC64_STRINGPARSING_DEFS_H
+#define SIMDJSON_PPC64_STRINGPARSING_DEFS_H
 
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/ppc64/simd.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
+namespace simdjson {
+namespace ppc64 {
+namespace {
 
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
+using namespace simd;
 
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
+public:
+  static constexpr uint32_t BYTES_PROCESSED = 32;
+  simdjson_inline static backslash_and_quote
+  copy_and_find(const uint8_t *src, uint8_t *dst);
 
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
+  simdjson_inline bool has_quote_first() {
+    return ((bs_bits - 1) & quote_bits) != 0;
+  }
+  simdjson_inline bool has_backslash() { return bs_bits != 0; }
+  simdjson_inline int quote_index() {
+    return trailing_zeroes(quote_bits);
+  }
+  simdjson_inline int backslash_index() {
+    return trailing_zeroes(bs_bits);
   }
-}
-
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
-}
-
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
-}
 
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
+  uint32_t bs_bits;
+  uint32_t quote_bits;
+}; // struct backslash_and_quote
 
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
+simdjson_inline backslash_and_quote
+backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 31 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1),
+                "backslash and quote finder must process fewer than "
+                "SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v0(src);
+  simd8<uint8_t> v1(src + sizeof(v0));
+  v0.store(dst);
+  v1.store(dst + sizeof(v0));
 
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
+  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on
+  // PPC; therefore, we smash them together into a 64-byte mask and get the
+  // bitmask from there.
+  uint64_t bs_and_quote =
+      simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
+  return {
+      uint32_t(bs_and_quote),      // bs_bits
+      uint32_t(bs_and_quote >> 32) // quote_bits
+  };
 }
 
-} // namespace ondemand
-} // namespace icelake
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<icelake::ondemand::value_iterator>::simdjson_result(icelake::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::value_iterator>(std::forward<icelake::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<icelake::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<icelake::ondemand::value_iterator>(error) {}
-
+} // unnamed namespace
+} // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for icelake */
-
-
-/* end file simdjson/generic/ondemand/amalgamated.h for icelake */
-/* including simdjson/icelake/end.h: #include "simdjson/icelake/end.h" */
-/* begin file simdjson/icelake/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/icelake/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+#endif // SIMDJSON_PPC64_STRINGPARSING_DEFS_H
+/* end file simdjson/ppc64/stringparsing_defs.h */
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
-SIMDJSON_UNTARGET_REGION
+#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
+/* end file simdjson/ppc64/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for ppc64: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for ppc64 */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
 #endif
 
-/* undefining SIMDJSON_IMPLEMENTATION from "icelake" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/icelake/end.h */
-
-#endif // SIMDJSON_ICELAKE_ONDEMAND_H
-/* end file simdjson/icelake/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
-/* including simdjson/ppc64/ondemand.h: #include "simdjson/ppc64/ondemand.h" */
-/* begin file simdjson/ppc64/ondemand.h */
-#ifndef SIMDJSON_PPC64_ONDEMAND_H
-#define SIMDJSON_PPC64_ONDEMAND_H
-
-/* including simdjson/ppc64/begin.h: #include "simdjson/ppc64/begin.h" */
-/* begin file simdjson/ppc64/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "ppc64" */
-#define SIMDJSON_IMPLEMENTATION ppc64
-/* including simdjson/ppc64/base.h: #include "simdjson/ppc64/base.h" */
-/* begin file simdjson/ppc64/base.h */
-#ifndef SIMDJSON_PPC64_BASE_H
-#define SIMDJSON_PPC64_BASE_H
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for ppc64: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+namespace ppc64 {
 /**
- * Implementation for ALTIVEC (PPC64).
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
  */
-namespace ppc64 {
+namespace ondemand {
 
-class implementation;
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
 
-namespace {
-namespace simd {
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
-} // namespace simd
-} // unnamed namespace
+/** @copydoc simdjson::ppc64::number_type */
+using number_type = simdjson::ppc64::number_type;
+
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
+
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
 
+} // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_PPC64_BASE_H
-/* end file simdjson/ppc64/base.h */
-/* including simdjson/ppc64/intrinsics.h: #include "simdjson/ppc64/intrinsics.h" */
-/* begin file simdjson/ppc64/intrinsics.h */
-#ifndef SIMDJSON_PPC64_INTRINSICS_H
-#define SIMDJSON_PPC64_INTRINSICS_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for ppc64 */
+/* including simdjson/generic/ondemand/deserialize.h for ppc64: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for ppc64 */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-// This should be the correct header whether
-// you use visual studio or other compilers.
-#include <altivec.h>
+#include <concepts>
+namespace simdjson {
 
-// These are defined by altivec.h in GCC toolchain, it is safe to undef them.
-#ifdef bool
-#undef bool
-#endif
+namespace tag_invoke_fn_ns {
+void tag_invoke();
 
-#ifdef vector
-#undef vector
-#endif
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
 
-static_assert(sizeof(__vector unsigned char) <= simdjson::SIMDJSON_PADDING, "insufficient padding for ppc64");
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
 
-#endif //  SIMDJSON_PPC64_INTRINSICS_H
-/* end file simdjson/ppc64/intrinsics.h */
-/* including simdjson/ppc64/bitmanipulation.h: #include "simdjson/ppc64/bitmanipulation.h" */
-/* begin file simdjson/ppc64/bitmanipulation.h */
-#ifndef SIMDJSON_PPC64_BITMANIPULATION_H
-#define SIMDJSON_PPC64_BITMANIPULATION_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace {
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long ret;
-  // Search the mask data from least significant bit (LSB)
-  // to the most significant bit (MSB) for a set bit (1).
-  _BitScanForward64(&ret, input_num);
-  return (int)ret;
-#else  // SIMDJSON_REGULAR_VISUAL_STUDIO
-  return __builtin_ctzll(input_num);
-#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
-}
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
 
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num - 1);
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  unsigned long leading_zero = 0;
-  // Search the mask data from most significant bit (MSB)
-  // to least significant bit (LSB) for a set bit (1).
-  if (_BitScanReverse64(&leading_zero, input_num))
-    return (int)(63 - leading_zero);
-  else
-    return 64;
-#else
-  return __builtin_clzll(input_num);
-#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
 
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-simdjson_inline int count_ones(uint64_t input_num) {
-  // note: we do not support legacy 32-bit Windows in this kernel
-  return __popcnt64(input_num); // Visual Studio wants two underscores
-}
-#else
-simdjson_inline int count_ones(uint64_t input_num) {
-  return __builtin_popcountll(input_num);
-}
-#endif
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
 
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
-                                         uint64_t *result) {
-#if SIMDJSON_REGULAR_VISUAL_STUDIO
-  *result = value1 + value2;
-  return *result < value1;
-#else
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-#endif
-}
 
-} // unnamed namespace
-} // namespace ppc64
-} // namespace simdjson
+struct deserialize_tag;
 
-#endif // SIMDJSON_PPC64_BITMANIPULATION_H
-/* end file simdjson/ppc64/bitmanipulation.h */
-/* including simdjson/ppc64/bitmask.h: #include "simdjson/ppc64/bitmask.h" */
-/* begin file simdjson/ppc64/bitmask.h */
-#ifndef SIMDJSON_PPC64_BITMASK_H
-#define SIMDJSON_PPC64_BITMASK_H
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<ppc64::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
 
-namespace simdjson {
-namespace ppc64 {
-namespace {
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
 
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is
-// encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
-  // You can use the version below, however gcc sometimes miscompiles
-  // vec_pmsum_be, it happens somewhere around between 8 and 9th version.
-  // The performance boost was not noticeable, falling back to a usual
-  // implementation.
-  //   __vector unsigned long long all_ones = {~0ull, ~0ull};
-  //   __vector unsigned long long mask = {bitmask, 0};
-  //   // Clang and GCC return different values for pmsum for ull so cast it to one.
-  //   // Generally it is not specified by ALTIVEC ISA what is returned by
-  //   // vec_pmsum_be.
-  // #if defined(__LITTLE_ENDIAN__)
-  //   return (uint64_t)(((__vector unsigned long long)vec_pmsum_be(all_ones, mask))[0]);
-  // #else
-  //   return (uint64_t)(((__vector unsigned long long)vec_pmsum_be(all_ones, mask))[1]);
-  // #endif
-  bitmask ^= bitmask << 1;
-  bitmask ^= bitmask << 2;
-  bitmask ^= bitmask << 4;
-  bitmask ^= bitmask << 8;
-  bitmask ^= bitmask << 16;
-  bitmask ^= bitmask << 32;
-  return bitmask;
-}
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-} // unnamed namespace
-} // namespace ppc64
-} // namespace simdjson
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
 
-#endif
-/* end file simdjson/ppc64/bitmask.h */
-/* including simdjson/ppc64/numberparsing_defs.h: #include "simdjson/ppc64/numberparsing_defs.h" */
-/* begin file simdjson/ppc64/numberparsing_defs.h */
-#ifndef SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
-#define SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = ppc64::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = ppc64::ondemand::value;
+  using document_type = ppc64::ondemand::document;
+  using document_reference_type = ppc64::ondemand::document_reference;
 
-#include <cstring>
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-#if defined(__linux__)
-#include <byteswap.h>
-#elif defined(__FreeBSD__)
-#include <sys/endian.h>
-#endif
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-namespace simdjson {
-namespace ppc64 {
-namespace numberparsing {
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-// we don't have appropriate instructions, so let us use a scalar function
-// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
-/** @private */
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  uint64_t val;
-  std::memcpy(&val, chars, sizeof(uint64_t));
-#ifdef __BIG_ENDIAN__
-#if defined(__linux__)
-  val = bswap_64(val);
-#elif defined(__FreeBSD__)
-  val = bswap64(val);
-#endif
-#endif
-  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
-  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
-  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
-}
 
-/** @private */
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-#if SIMDJSON_IS_ARM64
-  // ARM64 has native support for 64-bit multiplications, no need to emultate
-  answer.high = __umulh(value1, value2);
-  answer.low = value1 * value2;
-#else
-  answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
-#endif // SIMDJSON_IS_ARM64
-#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
-#endif
-  return answer;
-}
+} deserialize{};
 
-} // namespace numberparsing
-} // namespace ppc64
 } // namespace simdjson
 
-#ifndef SIMDJSON_SWAR_NUMBER_PARSING
-#if SIMDJSON_IS_BIG_ENDIAN
-#define SIMDJSON_SWAR_NUMBER_PARSING 0
-#else
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-#endif
-#endif
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
 
-#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
-/* end file simdjson/ppc64/numberparsing_defs.h */
-/* including simdjson/ppc64/simd.h: #include "simdjson/ppc64/simd.h" */
-/* begin file simdjson/ppc64/simd.h */
-#ifndef SIMDJSON_PPC64_SIMD_H
-#define SIMDJSON_PPC64_SIMD_H
+/* end file simdjson/generic/ondemand/deserialize.h for ppc64 */
+/* including simdjson/generic/ondemand/value_iterator.h for ppc64: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <type_traits>
-
 namespace simdjson {
 namespace ppc64 {
-namespace {
-namespace simd {
+namespace ondemand {
 
-using __m128i = __vector unsigned char;
+/**
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
+ *
+ * @private This is not intended for external use.
+ */
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
+  /**
+   * The starting token index for this value
+   */
+  token_position _start_position{};
 
-template <typename Child> struct base {
-  __m128i value;
+public:
+  simdjson_inline value_iterator() noexcept = default;
 
-  // Zero constructor
-  simdjson_inline base() : value{__m128i()} {}
+  /**
+   * Denote that we're starting a document.
+   */
+  simdjson_inline void start_document() noexcept;
 
-  // Conversion from SIMD register
-  simdjson_inline base(const __m128i _value) : value(_value) {}
+  /**
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   *
+   * Optimized for scalars.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
 
-  // Conversion to SIMD register
-  simdjson_inline operator const __m128i &() const {
-    return this->value;
-  }
-  simdjson_inline operator __m128i &() { return this->value; }
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
 
-  // Bit operations
-  simdjson_inline Child operator|(const Child other) const {
-    return vec_or(this->value, (__m128i)other);
-  }
-  simdjson_inline Child operator&(const Child other) const {
-    return vec_and(this->value, (__m128i)other);
-  }
-  simdjson_inline Child operator^(const Child other) const {
-    return vec_xor(this->value, (__m128i)other);
-  }
-  simdjson_inline Child bit_andnot(const Child other) const {
-    return vec_andc(this->value, (__m128i)other);
-  }
-  simdjson_inline Child &operator|=(const Child other) {
-    auto this_cast = static_cast<Child*>(this);
-    *this_cast = *this_cast | other;
-    return *this_cast;
-  }
-  simdjson_inline Child &operator&=(const Child other) {
-    auto this_cast = static_cast<Child*>(this);
-    *this_cast = *this_cast & other;
-    return *this_cast;
-  }
-  simdjson_inline Child &operator^=(const Child other) {
-    auto this_cast = static_cast<Child*>(this);
-    *this_cast = *this_cast ^ other;
-    return *this_cast;
-  }
-};
+  /**
+   * Tell whether the iterator is at the start of the value
+   */
+  simdjson_inline bool at_start() const noexcept;
 
-template <typename T, typename Mask = simd8<bool>>
-struct base8 : base<simd8<T>> {
-  typedef uint16_t bitmask_t;
-  typedef uint32_t bitmask2_t;
+  /**
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   */
+  simdjson_inline bool is_open() const noexcept;
 
-  simdjson_inline base8() : base<simd8<T>>() {}
-  simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
+  /**
+   * Tell whether the value is at an object's first field (just after the {).
+   */
+  simdjson_inline bool at_first_field() const noexcept;
 
-  friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) {
-    return (__m128i)vec_cmpeq(lhs.value, (__m128i)rhs);
-  }
+  /**
+   * Abandon all iteration.
+   */
+  simdjson_inline void abandon() noexcept;
 
-  static const int SIZE = sizeof(base<simd8<T>>::value);
+  /**
+   * Get the child value as a value_iterator.
+   */
+  simdjson_inline value_iterator child_value() const noexcept;
 
-  template <int N = 1>
-  simdjson_inline simd8<T> prev(simd8<T> prev_chunk) const {
-    __m128i chunk = this->value;
-#ifdef __LITTLE_ENDIAN__
-    chunk = (__m128i)vec_reve(this->value);
-    prev_chunk = (__m128i)vec_reve((__m128i)prev_chunk);
-#endif
-    chunk = (__m128i)vec_sld((__m128i)prev_chunk, (__m128i)chunk, 16 - N);
-#ifdef __LITTLE_ENDIAN__
-    chunk = (__m128i)vec_reve((__m128i)chunk);
-#endif
-    return chunk;
-  }
-};
+  /**
+   * Get the depth of this value.
+   */
+  simdjson_inline int32_t depth() const noexcept;
 
-// SIMD byte mask type (returned by things like eq and gt)
-template <> struct simd8<bool> : base8<bool> {
-  static simdjson_inline simd8<bool> splat(bool _value) {
-    return (__m128i)vec_splats((unsigned char)(-(!!_value)));
-  }
+  /**
+   * Get the JSON type of this value.
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
 
-  simdjson_inline simd8() : base8<bool>() {}
-  simdjson_inline simd8(const __m128i _value)
-      : base8<bool>(_value) {}
-  // Splat constructor
-  simdjson_inline simd8(bool _value)
-      : base8<bool>(splat(_value)) {}
+  /**
+   * @addtogroup object Object iteration
+   *
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
+   *
+   * @{
+   */
 
-  simdjson_inline int to_bitmask() const {
-    __vector unsigned long long result;
-    const __m128i perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40,
-                               0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00};
+  /**
+   * Start an object iteration.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  /**
+   * Start an object iteration from the root.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  /**
+   * Checks whether an object could be started from the root. May be called by start_root_object.
+   *
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  /**
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  /**
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
-    result = ((__vector unsigned long long)vec_vbpermq((__m128i)this->value,
-                                                       (__m128i)perm_mask));
-#ifdef __LITTLE_ENDIAN__
-    return static_cast<int>(result[1]);
-#else
-    return static_cast<int>(result[0]);
-#endif
-  }
-  simdjson_inline bool any() const {
-    return !vec_all_eq(this->value, (__m128i)vec_splats(0));
-  }
-  simdjson_inline simd8<bool> operator~() const {
-    return this->value ^ (__m128i)splat(true);
-  }
-};
+  /**
+   * Moves to the next field in an object.
+   *
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
 
-template <typename T> struct base8_numeric : base8<T> {
-  static simdjson_inline simd8<T> splat(T value) {
-    (void)value;
-    return (__m128i)vec_splats(value);
-  }
-  static simdjson_inline simd8<T> zero() { return splat(0); }
-  static simdjson_inline simd8<T> load(const T values[16]) {
-    return (__m128i)(vec_vsx_ld(0, reinterpret_cast<const uint8_t *>(values)));
-  }
-  // Repeat 16 values as many times as necessary (usually for lookup tables)
-  static simdjson_inline simd8<T> repeat_16(T v0, T v1, T v2, T v3, T v4,
-                                                   T v5, T v6, T v7, T v8, T v9,
-                                                   T v10, T v11, T v12, T v13,
-                                                   T v14, T v15) {
-    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
-                    v14, v15);
-  }
+  /**
+   * Get the current field's key.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
 
-  simdjson_inline base8_numeric() : base8<T>() {}
-  simdjson_inline base8_numeric(const __m128i _value)
-      : base8<T>(_value) {}
-
-  // Store to array
-  simdjson_inline void store(T dst[16]) const {
-    vec_vsx_st(this->value, 0, reinterpret_cast<__m128i *>(dst));
-  }
+  /**
+   * Pass the : in the field and move to its value.
+   */
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
 
-  // Override to distinguish from bool version
-  simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  /**
+   * Find the next field with the given key.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
 
-  // Addition/subtraction are the same for signed and unsigned
-  simdjson_inline simd8<T> operator+(const simd8<T> other) const {
-    return (__m128i)((__m128i)this->value + (__m128i)other);
-  }
-  simdjson_inline simd8<T> operator-(const simd8<T> other) const {
-    return (__m128i)((__m128i)this->value - (__m128i)other);
-  }
-  simdjson_inline simd8<T> &operator+=(const simd8<T> other) {
-    *this = *this + other;
-    return *static_cast<simd8<T> *>(this);
-  }
-  simdjson_inline simd8<T> &operator-=(const simd8<T> other) {
-    *this = *this - other;
-    return *static_cast<simd8<T> *>(this);
-  }
+  /**
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
 
-  // Perform a lookup assuming the value is between 0 and 16 (undefined behavior
-  // for out of range values)
-  template <typename L>
-  simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-    return (__m128i)vec_perm((__m128i)lookup_table, (__m128i)lookup_table, this->value);
-  }
+  /**
+   * Find the field with the given key without regard to order, and *without* unescaping.
+   *
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
 
-  // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted
-  // as a bitset). Passing a 0 value for mask would be equivalent to writing out
-  // every byte to output. Only the first 16 - count_ones(mask) bytes of the
-  // result are significant but 16 bytes get written. Design consideration: it
-  // seems like a function with the signature simd8<L> compress(uint32_t mask)
-  // would be sensible, but the AVX ISA makes this kind of approach difficult.
-  template <typename L>
-  simdjson_inline void compress(uint16_t mask, L *output) const {
-    using internal::BitsSetTable256mul2;
-    using internal::pshufb_combine_table;
-    using internal::thintable_epi8;
-    // this particular implementation was inspired by work done by @animetosho
-    // we do it in two steps, first 8 bytes and then second 8 bytes
-    uint8_t mask1 = uint8_t(mask);      // least significant 8 bits
-    uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
-    // next line just loads the 64-bit values thintable_epi8[mask1] and
-    // thintable_epi8[mask2] into a 128-bit register, using only
-    // two instructions on most compilers.
-#ifdef __LITTLE_ENDIAN__
-    __m128i shufmask = (__m128i)(__vector unsigned long long){
-        thintable_epi8[mask1], thintable_epi8[mask2]};
-#else
-    __m128i shufmask = (__m128i)(__vector unsigned long long){
-        thintable_epi8[mask2], thintable_epi8[mask1]};
-    shufmask = (__m128i)vec_reve((__m128i)shufmask);
-#endif
-    // we increment by 0x08 the second half of the mask
-    shufmask = ((__m128i)shufmask) +
-               ((__m128i)(__vector int){0, 0, 0x08080808, 0x08080808});
+  /** @} */
 
-    // this is the version "nearly pruned"
-    __m128i pruned = vec_perm(this->value, this->value, shufmask);
-    // we still need to put the two halves together.
-    // we compute the popcount of the first half:
-    int pop1 = BitsSetTable256mul2[mask1];
-    // then load the corresponding mask, what it does is to write
-    // only the first pop1 bytes from the first 8 bytes, and then
-    // it fills in with the bytes from the second 8 bytes + some filling
-    // at the end.
-    __m128i compactmask =
-        vec_vsx_ld(0, reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
-    __m128i answer = vec_perm(pruned, (__m128i)vec_splats(0), compactmask);
-    vec_vsx_st(answer, 0, reinterpret_cast<__m128i *>(output));
-  }
+  /**
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
+   */
 
-  template <typename L>
-  simdjson_inline simd8<L>
-  lookup_16(L replace0, L replace1, L replace2, L replace3, L replace4,
-            L replace5, L replace6, L replace7, L replace8, L replace9,
-            L replace10, L replace11, L replace12, L replace13, L replace14,
-            L replace15) const {
-    return lookup_16(simd8<L>::repeat_16(
-        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
-        replace7, replace8, replace9, replace10, replace11, replace12,
-        replace13, replace14, replace15));
-  }
-};
+  /**
+   * Check for an opening [ and start an array iteration.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  /**
+   * Check for an opening [ and start an array iteration while at the root.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  /**
+   * Checks whether an array could be started from the root. May be called by start_root_array.
+   *
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  /**
+   * Start an array iteration, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  /**
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
-// Signed bytes
-template <> struct simd8<int8_t> : base8_numeric<int8_t> {
-  simdjson_inline simd8() : base8_numeric<int8_t>() {}
-  simdjson_inline simd8(const __m128i _value)
-      : base8_numeric<int8_t>(_value) {}
-  // Splat constructor
-  simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-  // Array constructor
-  simdjson_inline simd8(const int8_t *values) : simd8(load(values)) {}
-  // Member-by-member initialization
-  simdjson_inline simd8(int8_t v0, int8_t v1, int8_t v2, int8_t v3,
-                               int8_t v4, int8_t v5, int8_t v6, int8_t v7,
-                               int8_t v8, int8_t v9, int8_t v10, int8_t v11,
-                               int8_t v12, int8_t v13, int8_t v14, int8_t v15)
-      : simd8((__m128i)(__vector signed char){v0, v1, v2, v3, v4, v5, v6, v7,
-                                              v8, v9, v10, v11, v12, v13, v14,
-                                              v15}) {}
-  // Repeat 16 values as many times as necessary (usually for lookup tables)
-  simdjson_inline static simd8<int8_t>
-  repeat_16(int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5,
-            int8_t v6, int8_t v7, int8_t v8, int8_t v9, int8_t v10, int8_t v11,
-            int8_t v12, int8_t v13, int8_t v14, int8_t v15) {
-    return simd8<int8_t>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
-                         v13, v14, v15);
-  }
+  /**
+   * Moves to the next element in an array.
+   *
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
-  // Order-sensitive comparisons
-  simdjson_inline simd8<int8_t>
-  max_val(const simd8<int8_t> other) const {
-    return (__m128i)vec_max((__vector signed char)this->value,
-                            (__vector signed char)(__m128i)other);
-  }
-  simdjson_inline simd8<int8_t>
-  min_val(const simd8<int8_t> other) const {
-    return (__m128i)vec_min((__vector signed char)this->value,
-                            (__vector signed char)(__m128i)other);
-  }
-  simdjson_inline simd8<bool>
-  operator>(const simd8<int8_t> other) const {
-    return (__m128i)vec_cmpgt((__vector signed char)this->value,
-                              (__vector signed char)(__m128i)other);
-  }
-  simdjson_inline simd8<bool>
-  operator<(const simd8<int8_t> other) const {
-    return (__m128i)vec_cmplt((__vector signed char)this->value,
-                              (__vector signed char)(__m128i)other);
-  }
-};
+  /**
+   * Get a child value iterator.
+   */
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
 
-// Unsigned bytes
-template <> struct simd8<uint8_t> : base8_numeric<uint8_t> {
-  simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-  simdjson_inline simd8(const __m128i _value)
-      : base8_numeric<uint8_t>(_value) {}
-  // Splat constructor
-  simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-  // Array constructor
-  simdjson_inline simd8(const uint8_t *values) : simd8(load(values)) {}
-  // Member-by-member initialization
-  simdjson_inline
-  simd8(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5,
-        uint8_t v6, uint8_t v7, uint8_t v8, uint8_t v9, uint8_t v10,
-        uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15)
-      : simd8((__m128i){v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
-                        v13, v14, v15}) {}
-  // Repeat 16 values as many times as necessary (usually for lookup tables)
-  simdjson_inline static simd8<uint8_t>
-  repeat_16(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4,
-            uint8_t v5, uint8_t v6, uint8_t v7, uint8_t v8, uint8_t v9,
-            uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14,
-            uint8_t v15) {
-    return simd8<uint8_t>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
-                          v13, v14, v15);
-  }
+  /** @} */
 
-  // Saturated math
-  simdjson_inline simd8<uint8_t>
-  saturating_add(const simd8<uint8_t> other) const {
-    return (__m128i)vec_adds(this->value, (__m128i)other);
-  }
-  simdjson_inline simd8<uint8_t>
-  saturating_sub(const simd8<uint8_t> other) const {
-    return (__m128i)vec_subs(this->value, (__m128i)other);
-  }
+  /**
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
+   */
 
-  // Order-specific operations
-  simdjson_inline simd8<uint8_t>
-  max_val(const simd8<uint8_t> other) const {
-    return (__m128i)vec_max(this->value, (__m128i)other);
-  }
-  simdjson_inline simd8<uint8_t>
-  min_val(const simd8<uint8_t> other) const {
-    return (__m128i)vec_min(this->value, (__m128i)other);
-  }
-  // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-  simdjson_inline simd8<uint8_t>
-  gt_bits(const simd8<uint8_t> other) const {
-    return this->saturating_sub(other);
-  }
-  // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-  simdjson_inline simd8<uint8_t>
-  lt_bits(const simd8<uint8_t> other) const {
-    return other.saturating_sub(*this);
-  }
-  simdjson_inline simd8<bool>
-  operator<=(const simd8<uint8_t> other) const {
-    return other.max_val(*this) == other;
-  }
-  simdjson_inline simd8<bool>
-  operator>=(const simd8<uint8_t> other) const {
-    return other.min_val(*this) == other;
-  }
-  simdjson_inline simd8<bool>
-  operator>(const simd8<uint8_t> other) const {
-    return this->gt_bits(other).any_bits_set();
-  }
-  simdjson_inline simd8<bool>
-  operator<(const simd8<uint8_t> other) const {
-    return this->gt_bits(other).any_bits_set();
-  }
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-  // Bit-specific operations
-  simdjson_inline simd8<bool> bits_not_set() const {
-    return (__m128i)vec_cmpeq(this->value, (__m128i)vec_splats(uint8_t(0)));
-  }
-  simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const {
-    return (*this & bits).bits_not_set();
-  }
-  simdjson_inline simd8<bool> any_bits_set() const {
-    return ~this->bits_not_set();
-  }
-  simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const {
-    return ~this->bits_not_set(bits);
-  }
-  simdjson_inline bool bits_not_set_anywhere() const {
-    return vec_all_eq(this->value, (__m128i)vec_splats(0));
-  }
-  simdjson_inline bool any_bits_set_anywhere() const {
-    return !bits_not_set_anywhere();
-  }
-  simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
-    return vec_all_eq(vec_and(this->value, (__m128i)bits),
-                      (__m128i)vec_splats(0));
-  }
-  simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const {
-    return !bits_not_set_anywhere(bits);
-  }
-  template <int N> simdjson_inline simd8<uint8_t> shr() const {
-    return simd8<uint8_t>(
-        (__m128i)vec_sr(this->value, (__m128i)vec_splat_u8(N)));
-  }
-  template <int N> simdjson_inline simd8<uint8_t> shl() const {
-    return simd8<uint8_t>(
-        (__m128i)vec_sl(this->value, (__m128i)vec_splat_u8(N)));
-  }
-};
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
 
-template <typename T> struct simd8x64 {
-  static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-  static_assert(NUM_CHUNKS == 4,
-                "PPC64 kernel should use four registers per 64-byte block.");
-  const simd8<T> chunks[NUM_CHUNKS];
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
 
-  simd8x64(const simd8x64<T> &o) = delete; // no copy allowed
-  simd8x64<T> &
-  operator=(const simd8<T>& other) = delete; // no assignment allowed
-  simd8x64() = delete;                      // no default constructor allowed
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
-  simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1,
-                                  const simd8<T> chunk2, const simd8<T> chunk3)
-      : chunks{chunk0, chunk1, chunk2, chunk3} {}
-  simdjson_inline simd8x64(const T ptr[64])
-      : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr + 16),
-               simd8<T>::load(ptr + 32), simd8<T>::load(ptr + 48)} {}
+  /** @} */
+protected:
+  /**
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  /**
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  /**
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
-  simdjson_inline void store(T ptr[64]) const {
-    this->chunks[0].store(ptr + sizeof(simd8<T>) * 0);
-    this->chunks[1].store(ptr + sizeof(simd8<T>) * 1);
-    this->chunks[2].store(ptr + sizeof(simd8<T>) * 2);
-    this->chunks[3].store(ptr + sizeof(simd8<T>) * 3);
-  }
+  /**
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
+   *
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
 
-  simdjson_inline simd8<T> reduce_or() const {
-    return (this->chunks[0] | this->chunks[1]) |
-           (this->chunks[2] | this->chunks[3]);
-  }
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
 
-  simdjson_inline uint64_t compress(uint64_t mask, T *output) const {
-    this->chunks[0].compress(uint16_t(mask), output);
-    this->chunks[1].compress(uint16_t(mask >> 16),
-                             output + 16 - count_ones(mask & 0xFFFF));
-    this->chunks[2].compress(uint16_t(mask >> 32),
-                             output + 32 - count_ones(mask & 0xFFFFFFFF));
-    this->chunks[3].compress(uint16_t(mask >> 48),
-                             output + 48 - count_ones(mask & 0xFFFFFFFFFFFF));
-    return 64 - count_ones(mask);
-  }
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
+   *
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   */
 
-  simdjson_inline uint64_t to_bitmask() const {
-    uint64_t r0 = uint32_t(this->chunks[0].to_bitmask());
-    uint64_t r1 = this->chunks[1].to_bitmask();
-    uint64_t r2 = this->chunks[2].to_bitmask();
-    uint64_t r3 = this->chunks[3].to_bitmask();
-    return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
-  }
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
 
-  simdjson_inline uint64_t eq(const T m) const {
-    const simd8<T> mask = simd8<T>::splat(m);
-    return simd8x64<bool>(this->chunks[0] == mask, this->chunks[1] == mask,
-                          this->chunks[2] == mask, this->chunks[3] == mask)
-        .to_bitmask();
-  }
-
-  simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-    return simd8x64<bool>(this->chunks[0] == other.chunks[0],
-                          this->chunks[1] == other.chunks[1],
-                          this->chunks[2] == other.chunks[2],
-                          this->chunks[3] == other.chunks[3])
-        .to_bitmask();
-  }
-
-  simdjson_inline uint64_t lteq(const T m) const {
-    const simd8<T> mask = simd8<T>::splat(m);
-    return simd8x64<bool>(this->chunks[0] <= mask, this->chunks[1] <= mask,
-                          this->chunks[2] <= mask, this->chunks[3] <= mask)
-        .to_bitmask();
-  }
-}; // struct simd8x64<T>
-
-} // namespace simd
-} // unnamed namespace
-} // namespace ppc64
-} // namespace simdjson
-
-#endif // SIMDJSON_PPC64_SIMD_INPUT_H
-/* end file simdjson/ppc64/simd.h */
-/* including simdjson/ppc64/stringparsing_defs.h: #include "simdjson/ppc64/stringparsing_defs.h" */
-/* begin file simdjson/ppc64/stringparsing_defs.h */
-#ifndef SIMDJSON_PPC64_STRINGPARSING_DEFS_H
-#define SIMDJSON_PPC64_STRINGPARSING_DEFS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/ppc64/simd.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace {
-
-using namespace simd;
-
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 32;
-  simdjson_inline static backslash_and_quote
-  copy_and_find(const uint8_t *src, uint8_t *dst);
-
-  simdjson_inline bool has_quote_first() {
-    return ((bs_bits - 1) & quote_bits) != 0;
-  }
-  simdjson_inline bool has_backslash() { return bs_bits != 0; }
-  simdjson_inline int quote_index() {
-    return trailing_zeroes(quote_bits);
-  }
-  simdjson_inline int backslash_index() {
-    return trailing_zeroes(bs_bits);
-  }
-
-  uint32_t bs_bits;
-  uint32_t quote_bits;
-}; // struct backslash_and_quote
-
-simdjson_inline backslash_and_quote
-backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 31 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1),
-                "backslash and quote finder must process fewer than "
-                "SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v0(src);
-  simd8<uint8_t> v1(src + sizeof(v0));
-  v0.store(dst);
-  v1.store(dst + sizeof(v0));
-
-  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on
-  // PPC; therefore, we smash them together into a 64-byte mask and get the
-  // bitmask from there.
-  uint64_t bs_and_quote =
-      simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
-  return {
-      uint32_t(bs_and_quote),      // bs_bits
-      uint32_t(bs_and_quote >> 32) // quote_bits
-  };
-}
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
 
-} // unnamed namespace
-} // namespace ppc64
-} // namespace simdjson
 
-#endif // SIMDJSON_PPC64_STRINGPARSING_DEFS_H
-/* end file simdjson/ppc64/stringparsing_defs.h */
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
 
-#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
-/* end file simdjson/ppc64/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for ppc64: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for ppc64 */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
-#endif
+  /**
+   * Advance to a place expecting a value (increasing depth).
+   *
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
+   */
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
 
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for ppc64: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  simdjson_inline bool is_at_start() const noexcept;
+  /**
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
+   *
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   */
+  simdjson_inline bool is_at_iterator_start() const noexcept;
 
-namespace simdjson {
-namespace ppc64 {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
+  /**
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
+   *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
+   */
+  simdjson_inline bool is_at_key() const noexcept;
 
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-/** @copydoc simdjson::ppc64::number_type */
-using number_type = simdjson::ppc64::number_type;
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
 
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
+  friend class document;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
 } // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for ppc64 */
-/* including simdjson/generic/ondemand/deserialize.h for ppc64: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for ppc64 */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
 namespace simdjson {
 
-namespace tag_invoke_fn_ns {
-void tag_invoke();
-
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
-
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
-
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+template<>
+struct simdjson_result<ppc64::ondemand::value_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::value_iterator> {
+public:
+  simdjson_inline simdjson_result(ppc64::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 };
 
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
-
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
-
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
-
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
-
-
-struct deserialize_tag;
-
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<ppc64::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<ppc64::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<ppc64::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<ppc64::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
-
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
-
-template <typename T, typename ValT = ppc64::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
-
-template <typename T, typename ValT = ppc64::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-template <typename T, typename ValT = ppc64::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
-
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = ppc64::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = ppc64::ondemand::value;
-  using document_type = ppc64::ondemand::document;
-  using document_reference_type = ppc64::ondemand::document_reference;
-
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-
-} deserialize{};
-
 } // namespace simdjson
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for ppc64 */
-/* including simdjson/generic/ondemand/value_iterator.h for ppc64: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for ppc64 */
+/* including simdjson/generic/ondemand/value.h for ppc64: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace ppc64 {
 namespace ondemand {
-
 /**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
- *
- * @private This is not intended for external use.
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
  */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
-
+class value {
 public:
-  simdjson_inline value_iterator() noexcept = default;
-
   /**
-   * Denote that we're starting a document.
+   * Create a new invalid value.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline void start_document() noexcept;
+  simdjson_inline value() noexcept = default;
 
   /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   * Get this value as the given type.
    *
-   * Optimized for scalars.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
 
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
 
   /**
-   * Tell whether the iterator is at the start of the value
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline bool at_start() const noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline bool is_open() const noexcept;
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
   /**
-   * Tell whether the value is at an object's first field (just after the {).
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline bool at_first_field() const noexcept;
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
   /**
-   * Abandon all iteration.
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline void abandon() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
   /**
-   * Get the child value as a value_iterator.
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline value_iterator child_value() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
   /**
-   * Get the depth of this value.
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline int32_t depth() const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
   /**
-   * Get the JSON type of this value.
+   * Cast this JSON value (inside string) to a signed integer.
    *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
   /**
-   * @addtogroup object Object iteration
-   *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
+   * Cast this JSON value to a double.
    *
-   * @{
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * Start an object iteration.
+   * Cast this JSON value (inside string) to a double
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+
   /**
-   * Start an object iteration from the root.
+   * Cast this JSON value to a string.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
-  /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
-  /**
-   * Start an object iteration after the user has already checked and moved past the {.
+   * Equivalent to get<std::string_view>().
    *
-   * Does not move the iterator unless the object is empty ({}).
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
-  /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
    *
-   * Does not move the iterator unless the object is empty ({}).
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
 
   /**
-   * Moves to the next field in an object.
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
 
   /**
-   * Get the current field's key.
+   * Cast this JSON value to a "wobbly" string.
+   *
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
 
   /**
-   * Pass the : in the field and move to its value.
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
    */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
 
   /**
-   * Find the next field with the given key.
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   * Assumes you have called next_field() or otherwise matched the previous value.
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
    *
-   * This means the iterator must be sitting at the next key:
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  /**
+   * Cast this JSON value to an array.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
    */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
-
+  simdjson_inline operator array() noexcept(false);
   /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
+   * Cast this JSON value to an object.
    *
-   * Assumes you have called next_field() or otherwise matched the previous value.
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
    *
-   * This means the iterator must be sitting at the next key:
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
-
+  simdjson_inline operator double() noexcept(false);
   /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
+   * Cast this JSON value to a string.
    *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * Assumes you have called next_field() or otherwise matched the previous value.
+   * Equivalent to get<std::string_view>().
    *
-   * This means the iterator must be sitting at the next key:
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
-
-  /** @} */
-
+  simdjson_inline operator raw_json_string() noexcept(false);
   /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
+  simdjson_inline operator bool() noexcept(false);
+#endif
 
   /**
-   * Check for an opening [ and start an array iteration.
+   * Begin array iteration.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
+   * Part of the std::iterable interface.
+   *
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
   /**
-   * Check for an opening [ and start an array iteration while at the root.
+   * Sentinel representing the end of the array.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * Part of the std::iterable interface.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
   /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Start an array iteration, after the user has already checked and moved past the [.
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
   /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
-   *
-   * Does not move the iterator unless the array is empty ([]).
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
-
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
   /**
-   * Moves to the next element in an array.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
 
-  /**
-   * Get a child value iterator.
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
-
-  /** @} */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
 
   /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
-
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
-
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
-
-  /** @} */
-protected:
   /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
   /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
   /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
+   * Checks whether the value is a string.
    *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
   /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
+   * Checks whether the value is a negative number.
    *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
-
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
-
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
    *
-   * ({"globals":{"a":{"shadowable":[}}}})
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
    *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
    *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
    *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   * @returns the type of the number
    */
-
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
-
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
-
-
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * Advance to a place expecting a value (increasing depth).
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
    */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
-
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-  simdjson_inline bool is_at_start() const noexcept;
   /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
+   * Get the raw JSON for this token.
    *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
    */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
+  simdjson_inline std::string_view raw_json_token() noexcept;
 
   /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
    *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  simdjson_inline bool is_at_key() const noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
 
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
 
-  /** @copydoc error_code json_iterator::position() const noexcept; */
-  simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+
+protected:
+  /**
+   * Create a value.
+   */
+  simdjson_inline value(const value_iterator &iter) noexcept;
+
+  /**
+   * Skip this value, allowing iteration to continue.
+   */
+  simdjson_inline void skip() noexcept;
+
+  /**
+   * Start a value at the current position.
+   *
+   * (It should already be started; this is just a self-documentation method.)
+   */
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
+
+  /**
+   * Resume a value.
+   */
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
+
+  /**
+   * Get the object, starting or resuming it as necessary
+   */
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
+
+  value_iterator iter{};
 
   friend class document;
+  friend class array_iterator;
+  friend class field;
   friend class object;
-  friend class array;
-  friend class value;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
   friend class field;
-}; // value_iterator
+};
 
 } // namespace ondemand
 } // namespace ppc64
@@ -80780,711 +78698,677 @@ class value_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::value_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::value_iterator> {
+struct simdjson_result<ppc64::ondemand::value> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::value> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::value &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-};
 
-} // namespace simdjson
+  simdjson_inline simdjson_result<ppc64::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::object> get_object() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for ppc64 */
-/* including simdjson/generic/ondemand/value.h for ppc64: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
 
-#include <type_traits>
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
 
-namespace simdjson {
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator ppc64::ondemand::array() noexcept(false);
+  simdjson_inline operator ppc64::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator ppc64::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> end() & noexcept;
 
-namespace ppc64 {
-namespace ondemand {
-/**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
- */
-class value {
-public:
   /**
-   * Create a new invalid value.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_inline value() noexcept = default;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(const char *key) noexcept;
 
   /**
-   * Get this value as the given type.
+   * Look up a field by name on an object, without regard to key order.
    *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-
+  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<ppc64::ondemand::value> operator[](int) noexcept = delete;
 
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   * Get the type of this JSON value.
    *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
    */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+  simdjson_inline simdjson_result<ppc64::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<ppc64::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::number> get_number() noexcept;
+
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for ppc64 */
+/* including simdjson/generic/ondemand/logger.h for ppc64: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
+
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
+};
+
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
 #else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
+  static constexpr const bool LOG_ENABLED = false;
 #endif
-  }
 
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+} // namespace logger
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for ppc64 */
+/* including simdjson/generic/ondemand/token_iterator.h for ppc64: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+/**
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
+ *
+ * @private This is not intended for external use.
+ */
+class token_iterator {
+public:
   /**
-   * Cast this JSON value to an object.
+   * Create a new invalid token_iterator.
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
 
   /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * Advance to the next token (returning the current one).
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
   /**
-   * Cast this JSON value (inside string) to a unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   * Reports the current offset in bytes from the start of the underlying buffer.
    */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-
+  simdjson_inline uint32_t current_offset() const noexcept;
   /**
-   * Cast this JSON value to a signed integer.
+   * Get the JSON text for a given token (relative).
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
    */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Cast this JSON value (inside string) to a signed integer.
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
 
   /**
-   * Cast this JSON value to a double.
+   * Get the JSON text for a given token.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
    *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Cast this JSON value (inside string) to a double
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token.
    */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Cast this JSON value to a string.
+   * Get the maximum length of the JSON text for a root token.
    *
-   * The string is guaranteed to be valid UTF-8.
+   * The length will include any whitespace at the end of the token.
    *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * @param position The position of the token (start of the document).
    */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Return the current index.
+   */
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Reset to a previously saved index.
+   */
+  simdjson_inline void set_position(token_position target_position) noexcept;
+
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
+
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+
+protected:
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
 
   /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   * Get the index of the JSON text for a given token (relative).
    *
-   * The string is guaranteed to be valid UTF-8.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
+   */
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  /**
+   * Get the index of the JSON text for a given token.
    *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
    *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
 
+  const uint8_t *buf{};
+  token_position _position{};
+
+  friend class json_iterator;
+  friend class value_iterator;
+  friend class object;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+};
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<ppc64::ondemand::token_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::token_iterator> {
+public:
+  simdjson_inline simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for ppc64 */
+/* including simdjson/generic/ondemand/json_iterator.h for ppc64: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+/**
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
+ */
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
   /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
+   * Next free location in the string buffer.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
    */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  uint8_t *_string_buf_loc{};
   /**
-   * Cast this JSON value to a raw_json_string.
+   * JSON error, if there is one.
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
    */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-
+  error_code error{SUCCESS};
   /**
-   * Cast this JSON value to a bool.
+   * Depth of the current token in the JSON.
    *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
    */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  depth_t _depth{};
+  /**
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
+   */
+  token_position _root{};
+  /**
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
+   */
+  bool _streaming{false};
 
+public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   * Skips a JSON value, whether it is a scalar, array or object.
    */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
-#if SIMDJSON_EXCEPTIONS
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
+   * Tell whether the iterator is still at the start
    */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline bool at_root() const noexcept;
+
   /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
    */
-  simdjson_inline operator array() noexcept(false);
+  simdjson_inline bool streaming() const noexcept;
+
   /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   * Get the root value iterator
    */
-  simdjson_inline operator object() noexcept(false);
+  simdjson_inline token_position root_position() const noexcept;
   /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * Assert that we are at the document depth (== 1)
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline void assert_at_document_depth() const noexcept;
   /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   * Assert that we are at the root of the document
    */
-  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline void assert_at_root() const noexcept;
+
   /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * Tell whether the iterator is at the EOF mark
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline bool at_end() const noexcept;
+
   /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * Tell whether the iterator is live (has not been moved).
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline bool is_alive() const noexcept;
+
   /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
    */
-  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline void abandon() noexcept;
+
   /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * Advance the current token without modifying depth.
    */
-  simdjson_inline operator bool() noexcept(false);
-#endif
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
 
   /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   * @return whether there is a single token
    */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline bool is_single_token() const noexcept;
+
   /**
-   * Sentinel representing the end of the array.
+   * Assert that there are at least the given number of tokens left.
    *
-   * Part of the std::iterable interface.
+   * Has no effect in release builds.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Assert that the given position addresses an actual token (is within bounds).
    *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
+   * Has no effect in release builds.
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Get the JSON text for a given token (relative).
    *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * The length will include any whitespace at the end of the token.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
-
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * Look up a field by name on an object, without regard to key order.
+   * Get a pointer to the current location in the input buffer.
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
+   */
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
+  /**
+   * Get the JSON text for a given token.
    *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
+   * @param position The position of the token to retrieve.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
-
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
   /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * The length will include any whitespace at the end of the token.
    *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   * Get the maximum length of the JSON text for the current root token.
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token to retrieve.
    */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
   /**
-   * Checks whether the value is a string.
+   * Get the JSON text for the last token in the document.
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * Checks whether the value is a negative number.
+   * Ascend one level.
    *
-   * @returns true if the number if negative.
+   * Validates that the depth - 1 == parent_depth.
+   *
+   * @param parent_depth the expected parent depth.
    */
-  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+
   /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
+   * Descend one level.
    *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
+   * Validates that the new depth == child_depth.
    *
-   * @returns true if the number if negative.
+   * @param child_depth the expected child depth.
    */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+
   /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
+   * Get current depth.
    */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline depth_t depth() const noexcept;
 
   /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
+   * Get current (writeable) location in the string buffer.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
   /**
-   * Get the raw JSON for this token.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   *
-   * See also value::raw_json().
-   */
-  simdjson_inline std::string_view raw_json_token() noexcept;
-
-  /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
   /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
 
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
-   *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
 
+  simdjson_inline token_position position() const noexcept;
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
    */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
 
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
 
-protected:
-  /**
-   * Create a value.
-   */
-  simdjson_inline value(const value_iterator &iter) noexcept;
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
 
-  /**
-   * Skip this value, allowing iteration to continue.
-   */
-  simdjson_inline void skip() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
 
   /**
-   * Start a value at the current position.
-   *
-   * (It should already be started; this is just a self-documentation method.)
+   * Returns the current location in the document if in bounds.
    */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+  inline simdjson_result<const char *> current_location() const noexcept;
 
   /**
-   * Resume a value.
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
    */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
-
+  inline void rewind() noexcept;
   /**
-   * Get the object, starting or resuming it as necessary
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
    */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
-
-  value_iterator iter{};
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
+  simdjson_inline token_position last_position() const noexcept;
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
+  simdjson_inline token_position end_position() const noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
 
   friend class document;
-  friend class array_iterator;
-  friend class field;
+  friend class document_stream;
   friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
+  friend class array;
+  friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
   friend class field;
-};
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
 
 } // namespace ondemand
 } // namespace ppc64
@@ -81493,204 +79377,189 @@ class value {
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::value> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::value> {
+struct simdjson_result<ppc64::ondemand::json_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::json_iterator> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::value &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+
   simdjson_inline simdjson_result() noexcept = default;
+};
 
-  simdjson_inline simdjson_result<ppc64::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::object> get_object() noexcept;
+} // namespace simdjson
 
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for ppc64 */
+/* including simdjson/generic/ondemand/json_type.h for ppc64: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
 
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator ppc64::ondemand::array() noexcept(false);
-  simdjson_inline operator ppc64::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator ppc64::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> end() & noexcept;
+/**
+ * The type of a JSON value.
+ */
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
+
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
 
   /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field(const char *key) noexcept;
-
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
   /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
    */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<ppc64::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<ppc64::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<ppc64::ondemand::value> operator[](int) noexcept = delete;
-
+  simdjson_inline bool is_uint64() const noexcept;
   /**
-   * Get the type of this JSON value.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   * return the value as a uint64_t, only valid if is_uint64() is true.
    */
-  simdjson_inline simdjson_result<ppc64::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<ppc64::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::number> get_number() noexcept;
-
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
+   */
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
-} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for ppc64 */
-/* including simdjson/generic/ondemand/logger.h for ppc64: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
+   */
+  simdjson_inline bool is_double() const noexcept;
+  /**
+   * return the value as a double, only valid if is_double() is true.
+   */
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
+   */
+  simdjson_inline double as_double() const noexcept;
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
 
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
+protected:
+  /**
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
+   */
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
+  /**
+   * End of friend declarations.
+   */
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
+  /**
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
+   */
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
 };
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
 #endif
 
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+namespace simdjson {
 
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+template<>
+struct simdjson_result<ppc64::ondemand::json_type> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::json_type> {
+public:
+  simdjson_inline simdjson_result(ppc64::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+};
 
-} // namespace logger
-} // namespace ondemand
-} // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for ppc64 */
-/* including simdjson/generic/ondemand/token_iterator.h for ppc64: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for ppc64 */
+/* including simdjson/generic/ondemand/raw_json_string.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -81698,132 +79567,177 @@ namespace ppc64 {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
+ *
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
+ *
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
  *
- * @private This is not intended for external use.
  */
-class token_iterator {
+class raw_json_string {
 public:
   /**
-   * Create a new invalid token_iterator.
+   * Create a new invalid raw_json_string.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * Advance to the next token (returning the current one).
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
-  /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
-   */
-  simdjson_inline uint32_t current_offset() const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * The given location must be just *after* the beginning quote (") in the JSON file.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * It *must* be terminated by a ", and be a valid JSON string.
+   */
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  /**
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  simdjson_inline const char * raw() const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
    *
-   * The length will include any whitespace at the end of the token.
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
 
   /**
-   * Get the JSON text for a given token.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
    *
-   * @param position The position of the token.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * The length will include any whitespace at the end of the token.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * @param position The position of the token.
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a root token.
-   *
-   * The length will include any whitespace at the end of the token.
-   *
-   * @param position The position of the token (start of the document).
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+
   /**
-   * Return the current index.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline token_position position() const noexcept;
+  simdjson_inline bool is_equal(const char* target) const noexcept;
+
   /**
-   * Reset to a previously saved index.
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
 
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
+private:
 
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
 
-protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+  /**
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
+   */
+  simdjson_inline void consume() noexcept { buf = nullptr; }
 
   /**
-   * Get the index of the JSON text for a given token (relative).
+   * Checks whether the inner pointer is non-null and thus usable.
+   */
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ## IMPORTANT: string_view lifetime
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+
   /**
-   * Get the index of the JSON text for a given token.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ## IMPORTANT: string_view lifetime
    *
-   * @param position The position of the token.
+   * The string_view is only valid until the next parse() call on the parser.
    *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
-
-  const uint8_t *buf{};
-  token_position _position{};
-
-  friend class json_iterator;
-  friend class value_iterator;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
   friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
 };
 
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+
+
 } // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
@@ -81831,339 +79745,398 @@ class token_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::token_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::token_iterator> {
+struct simdjson_result<ppc64::ondemand::raw_json_string> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::raw_json_string> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
   simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for ppc64 */
-/* including simdjson/generic/ondemand/json_iterator.h for ppc64: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for ppc64 */
+/* including simdjson/generic/ondemand/parser.h for ppc64: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
+ */
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
  *
- * @private This is not intended for external use.
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
  */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
-  /**
-   * Next free location in the string buffer.
-   *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
-   */
-  uint8_t *_string_buf_loc{};
-  /**
-   * JSON error, if there is one.
-   *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
-   *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
-   */
-  error_code error{SUCCESS};
-  /**
-   * Depth of the current token in the JSON.
-   *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
-   */
-  bool _streaming{false};
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
 
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
 public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
-
-  /**
-   * Tell whether the iterator is still at the start
-   */
-  simdjson_inline bool at_root() const noexcept;
-
-  /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
-   */
-  simdjson_inline bool streaming() const noexcept;
-
-  /**
-   * Get the root value iterator
-   */
-  simdjson_inline token_position root_position() const noexcept;
-  /**
-   * Assert that we are at the document depth (== 1)
-   */
-  simdjson_inline void assert_at_document_depth() const noexcept;
-  /**
-   * Assert that we are at the root of the document
-   */
-  simdjson_inline void assert_at_root() const noexcept;
-
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
-
   /**
-   * Tell whether the iterator is live (has not been moved).
+   * Create a JSON parser.
+   *
+   * The new parser will have zero capacity.
    */
-  simdjson_inline bool is_alive() const noexcept;
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
 
-  /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
-   */
-  simdjson_inline void abandon() noexcept;
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
 
-  /**
-   * Advance the current token without modifying depth.
-   */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Start iterating an on-demand JSON document.
    *
-   * @return whether there is a single token
-   */
-  simdjson_inline bool is_single_token() const noexcept;
-
-  /**
-   * Assert that there are at least the given number of tokens left.
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
-  /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   * ### IMPORTANT: Validate what you use
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * The length will include any whitespace at the end of the token.
+   * ### IMPORTANT: Document Lifetime
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
-   */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
-  /**
-   * Get a pointer to the current location in the input buffer.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### REQUIRED: Buffer Padding
    *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
-   */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
-  /**
-   * Get the JSON text for a given token.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### std::string references
    *
-   * @param position The position of the token to retrieve.
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
    *
-   * The length will include any whitespace at the end of the token.
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
    *
-   * @param position The position of the token to retrieve.
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   *
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
+
   /**
-   * Get the maximum length of the JSON text for the current root token.
+   * @private
    *
-   * The length will include any whitespace at the end of the token.
+   * Start iterating an on-demand JSON document.
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
-  /**
-   * Get the JSON text for the last token in the document.
+   *   ondemand::parser parser;
+   *   json_iterator doc = parser.iterate(json);
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
-
-  /**
-   * Ascend one level.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * Validates that the depth - 1 == parent_depth.
+   * ### IMPORTANT: Document Lifetime
    *
-   * @param parent_depth the expected parent depth.
-   */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
-
-  /**
-   * Descend one level.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * Validates that the new depth == child_depth.
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
    *
-   * @param child_depth the expected child depth.
-   */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
-
-  /**
-   * Get current depth.
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * @param json The JSON to parse.
+   *
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline depth_t depth() const noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
 
-  /**
-   * Get current (writeable) location in the string buffer.
-   */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
 
   /**
-   * Report an unrecoverable error, preventing further iteration.
+   * Parse a buffer containing many JSON documents.
    *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
+   *
+   * No copy of the input buffer is made.
+   *
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   *
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
+   *
+   * ### Format
+   *
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
+   *
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
+   *
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
+   *
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * ### Threads
+   *
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
+   *
+   * ### Parser Capacity
+   *
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
+   *
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   */
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
 
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
 
   /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
+   *
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   *
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
 
-  simdjson_inline token_position position() const noexcept;
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
-
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
-
-  simdjson_inline error_code consume_character(char c) noexcept;
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
-#endif
-
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-
+  bool threaded{true};
+  #else
   /**
-   * Returns the current location in the document if in bounds.
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
+  bool threaded{false};
+  #endif
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   *
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
+   */
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
 
   /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   *
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
+   *
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid as long as the bytes in dst.
+   *
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  inline void rewind() noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
    */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
+#endif
 
-  friend class document;
+private:
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  std::unique_ptr<token_position[]> start_positions{};
+#endif
+
+  friend class json_iterator;
   friend class document_stream;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
+};
 
 } // namespace ondemand
 } // namespace ppc64
@@ -82172,27 +80145,28 @@ class json_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::json_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::json_iterator> {
+struct simdjson_result<ppc64::ondemand::parser> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::parser> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::parser &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-
   simdjson_inline simdjson_result() noexcept = default;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for ppc64 */
-/* including simdjson/generic/ondemand/json_type.h for ppc64: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for ppc64 */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for ppc64: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -82200,133 +80174,180 @@ namespace ppc64 {
 namespace ondemand {
 
 /**
- * The type of a JSON value.
- */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
-
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
+ * A forward-only JSON array.
  */
-struct number {
+class array {
+public:
+  /**
+   * Create a new invalid array.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline array() noexcept = default;
 
   /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+   * Begin array iteration.
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
+   * Part of the std::iterable interface.
    */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  simdjson_inline bool is_uint64() const noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
   /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   *
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    */
-  simdjson_inline bool is_int64() const noexcept;
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
   /**
-   * return the value as a int64_t, only valid if is_int64() is true.
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
+   *
+   * @returns true if the array contains some elements (not empty)
    */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
+  /**
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline bool is_double() const noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+protected:
   /**
-   * return the value as a double, only valid if is_double() is true.
+   * Go to the end of the array, no matter where you are right now.
    */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
+  simdjson_inline error_code consume() noexcept;
 
   /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Begin array iteration.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
    */
-  simdjson_inline double as_double() const noexcept;
-
-
-protected:
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
   /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
+   * Begin array iteration from the root.
+   *
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
    */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
   /**
-   * End of friend declarations.
+   * Begin array iteration.
+   *
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
+   *
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
    */
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
 
   /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
+   *
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
    */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
+  simdjson_inline array(const value_iterator &iter) noexcept;
 
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+  /**
+   * Iterator marking current position.
+   *
+   * iter.is_alive() == false indicates iteration is complete.
+   */
+  value_iterator iter{};
 
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
+};
 
 } // namespace ondemand
 } // namespace ppc64
@@ -82335,204 +80356,100 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &t
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::json_type> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::json_type> {
+struct simdjson_result<ppc64::ondemand::array> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::array> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::json_type &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::array &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for ppc64 */
-/* including simdjson/generic/ondemand/raw_json_string.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for ppc64 */
+/* including simdjson/generic/ondemand/array_iterator.h for ppc64: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
 /**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
- *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
+ * A forward-only JSON array.
  *
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
  */
-class raw_json_string {
+class array_iterator {
 public:
-  /**
-   * Create a new invalid raw_json_string.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline raw_json_string() noexcept = default;
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
 
-  /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
-   *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
-   *
-   * It *must* be terminated by a ", and be a valid JSON string.
-   */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
-  /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
-   *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
-   */
-  simdjson_inline const char * raw() const noexcept;
+  //
+  // Iterator interface
+  //
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
-   *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * Get the current element.
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * Part of the std::iterator interface.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
-
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
-   *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
+   * Check if we are at the end of the JSON.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Part of the std::iterator interface.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * @return true if there are no more elements in the JSON array.
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
-
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Check if there are more elements in the JSON array.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * Part of the std::iterator interface.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
-   */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
-
-  /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
-
-  /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * @return true if there are more elements in the JSON array.
    */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
-
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
+  simdjson_inline array_iterator &operator++() noexcept;
 
 private:
+  value_iterator iter{};
 
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
 
-  /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
-   */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
-
-  /**
-   * Checks whether the inner pointer is non-null and thus usable.
-   */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
-
-  /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
-
-  /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
 };
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
-
-/**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
- */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
-
-
 } // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
@@ -82540,458 +80457,375 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
 namespace simdjson {
 
 template<>
-struct simdjson_result<ppc64::ondemand::raw_json_string> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::raw_json_string> {
+struct simdjson_result<ppc64::ondemand::array_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator> {
 public:
-  simdjson_inline simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(ppc64::ondemand::array_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept;
+  //
+  // Iterator interface
+  //
+
+  simdjson_inline simdjson_result<ppc64::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<ppc64::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<ppc64::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> &operator++() noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for ppc64 */
-/* including simdjson/generic/ondemand/parser.h for ppc64: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for ppc64 */
+/* including simdjson/generic/ondemand/document.h for ppc64: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
 /**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
+ * A JSON document. It holds a json_iterator instance.
  *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
-
-/**
- * A JSON fragment iterator.
+ * Used by tokens to get text, and string buffer location.
  *
- * This holds the actual iterator as well as the buffer for writing strings.
+ * You must keep the document around during iteration.
  */
-class parser {
+class document {
 public:
   /**
-   * Create a JSON parser.
+   * Create a new invalid document.
    *
-   * The new parser will have zero capacity.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
-
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
-
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
 
   /**
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
+   * Cast this JSON value to an array.
    *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
+   */
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  /**
+   * Cast this JSON value to an object.
    *
-   * ### IMPORTANT: Validate what you use
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   */
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  /**
+   * Cast this JSON value to an unsigned integer.
    *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to an unsigned integer.
    *
-   * ### IMPORTANT: Buffer Lifetime
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a signed integer.
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  /**
+   * Cast this JSON value (inside string) to a signed integer.
    *
-   * ### IMPORTANT: Document Lifetime
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  /**
+   * Cast this JSON value to a double.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+
+  /**
+   * Cast this JSON value (inside string) to a double.
    *
-   * ### REQUIRED: Buffer Padding
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  /**
+   * Cast this JSON value to a string.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * ### std::string references
+   * Important: Calling get_string() twice on the same document is an error.
    *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
+   * The string is guaranteed to be valid UTF-8.
    *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
    *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
-
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
   /**
-   * @private
-   *
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
-   *
-   * ### IMPORTANT: Buffer Lifetime
+   * Cast this JSON value to a string.
    *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
    *
-   * ### IMPORTANT: Document Lifetime
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
    *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
    *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * ### REQUIRED: Buffer Padding
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  /**
+   * Cast this JSON value to a bool.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
    *
-   * @param json The JSON to parse.
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
    *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
    */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
-
+  simdjson_inline simdjson_result<value> get_value() noexcept;
 
   /**
-   * Parse a buffer containing many JSON documents.
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  /**
+   * Get this value as the given type.
    *
-   * No copy of the input buffer is made.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
    *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
    *
-   * ### Format
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
    *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
-   *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
-   *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
-   *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * ### Threads
-   *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
-   *
-   * ### Parser Capacity
-   *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
-   *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
    */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
+#if SIMDJSON_EXCEPTIONS
   /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
    *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
+   * @returns An instance of type T
    */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
 
-  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
    */
-  bool threaded{true};
-  #else
+  simdjson_inline operator array() & noexcept(false);
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline operator object() & noexcept(false);
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid as long as the bytes in dst.
+   * Cast this JSON value to an unsigned integer.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
-
+  simdjson_inline operator uint64_t() noexcept(false);
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
-   *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
-   *
-   * ## IMPORTANT: string_view lifetime
+   * Cast this JSON value to a signed integer.
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline operator double() noexcept(false);
   /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
-
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
-
-  friend class json_iterator;
-  friend class document_stream;
-};
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<ppc64::ondemand::parser> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::parser> {
-public:
-  simdjson_inline simdjson_result(ppc64::ondemand::parser &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for ppc64 */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for ppc64: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-/**
- * A forward-only JSON array.
- */
-class array {
-public:
+  simdjson_inline operator std::string_view() noexcept(false);
   /**
-   * Create a new invalid array.
+   * Cast this JSON value to a raw_json_string.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_inline array() noexcept = default;
-
+  simdjson_inline operator raw_json_string() noexcept(false);
   /**
-   * Begin array iteration.
+   * Cast this JSON value to a bool.
    *
-   * Part of the std::iterable interface.
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  simdjson_inline operator bool() noexcept(false);
   /**
-   * Sentinel representing the end of the array.
+   * Cast this JSON value to a value when the document is an object or an array.
    *
-   * Part of the std::iterable interface.
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
    */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  simdjson_inline operator value() noexcept(false);
+#endif
   /**
    * This method scans the array and counts the number of elements.
    * The count_elements method should always be called before you have begun
@@ -83003,460 +80837,416 @@ class array {
    * there is a missing comma), then an error is returned and it is no longer
    * safe to continue. Note that count_elements() does not validate the JSON values,
    * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
    */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
    * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
    * there is a missing comma), then an error is returned and it is no longer
    * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * @returns true if the array contains some elements (not empty)
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * Begin array iteration.
    *
-   *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+
+  /**
+   * Look up a field by name on an object (order-sensitive).
    *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * Look up a field by name on an object, without regard to key order.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. E.g., the array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
   /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-protected:
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline error_code consume() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
   /**
-   * Begin array iteration.
+   * Checks whether the document is a negative number.
    *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @returns true if the number if negative.
    */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * Begin array iteration from the root.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   * @returns true if the number if negative.
    */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * Begin array iteration.
-   *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
    */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
    */
-  simdjson_inline array(const value_iterator &iter) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
   /**
-   * Iterator marking current position.
+   * Get the raw JSON for this token.
    *
-   * iter.is_alive() == false indicates iteration is complete.
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
    */
-  value_iterator iter{};
-
-  friend class value;
-  friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
-  friend class array_iterator;
-};
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<ppc64::ondemand::array> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::array> {
-public:
-  simdjson_inline simdjson_result(ppc64::ondemand::array &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for ppc64 */
-/* including simdjson/generic/ondemand/array_iterator.h for ppc64: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
 
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
+  /**
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
+   */
+  inline void rewind() noexcept;
+  /**
+   * Returns debugging information.
+   */
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
 
-/**
- * A forward-only JSON array.
- *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
- */
-class array_iterator {
-public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
 
-  //
-  // Iterator interface
-  //
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
 
   /**
-   * Get the current element.
+   * Returns the current depth in the document if in bounds.
    *
-   * Part of the std::iterator interface.
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
    */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline int32_t current_depth() const noexcept;
+
   /**
-   * Check if we are at the end of the JSON.
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
-   * Part of the std::iterator interface.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
    *
-   * @return true if there are no more elements in the JSON array.
-   */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
-  /**
-   * Check if there are more elements in the JSON array.
+   * It is allowed for a key to be the empty string:
    *
-   * Part of the std::iterator interface.
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
    *
-   * @return true if there are more elements in the JSON array.
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+
   /**
-   * Move to the next element.
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
    *
-   * Part of the std::iterator interface.
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  simdjson_inline array_iterator &operator++() noexcept;
-
-private:
-  value_iterator iter{};
-
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
-
-  friend class array;
-  friend class value;
-  friend struct simdjson_result<array_iterator>;
-};
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
+  /**
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+protected:
+  /**
+   * Consumes the document.
+   */
+  simdjson_inline error_code consume() noexcept;
 
-namespace simdjson {
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
 
-template<>
-struct simdjson_result<ppc64::ondemand::array_iterator> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::array_iterator> {
-public:
-  simdjson_inline simdjson_result(ppc64::ondemand::array_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
 
   //
-  // Iterator interface
+  // Fields
   //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
 
-  simdjson_inline simdjson_result<ppc64::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<ppc64::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<ppc64::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> &operator++() noexcept;
+  friend class array_iterator;
+  friend class value;
+  friend class ondemand::parser;
+  friend class object;
+  friend class array;
+  friend class field;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
 };
 
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for ppc64 */
-/* including simdjson/generic/ondemand/document.h for ppc64: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
- *
- * Used by tokens to get text, and string buffer location.
- *
- * You must keep the document around during iteration.
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
  */
-class document {
+class document_reference {
 public:
-  /**
-   * Create a new invalid document.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
   simdjson_inline simdjson_result<array> get_array() & noexcept;
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
   simdjson_inline simdjson_result<object> get_object() & noexcept;
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
   simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
   simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: Calling get_string() twice on the same document is an error.
-   *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
   simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
   template <typename string_type>
   simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
   simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
   simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
   simdjson_inline simdjson_result<value> get_value() noexcept;
 
-  /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
   simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
   template <typename T>
   simdjson_inline simdjson_result<T> get() &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -83470,16 +81260,6 @@ class document {
     SIMDJSON_TRY(get<T>(out));
     return out;
   }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
   template<typename T>
   simdjson_inline simdjson_result<T> get() &&
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -83488,7 +81268,7 @@ class document {
     noexcept
 #endif
   {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
       return static_cast<document&>(*this).get<T>();
   }
 
@@ -83506,13 +81286,13 @@ class document {
   template<typename T>
   simdjson_inline error_code get(T &out) &
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
 #else
     noexcept
 #endif
   {
 #if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
+    if constexpr (custom_deserializable<T, document_reference>) {
         return deserialize(*this, out);
     } else {
 #endif // SIMDJSON_SUPPORTS_DESERIALIZATION
@@ -83530,503 +81310,68 @@ class document {
 #endif
   }
   /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
-
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
 #if SIMDJSON_EXCEPTIONS
-  /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
   template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
+  explicit simdjson_inline operator T() noexcept(false);
   simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
   simdjson_inline operator object() & noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
   simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
   simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
-   */
   simdjson_inline operator double() noexcept(false);
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
   simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
   simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
-   */
   simdjson_inline operator bool() noexcept(false);
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
   simdjson_inline operator value() noexcept(false);
 #endif
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   */
   simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   */
   simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
   simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
-   */
   simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
-   */
   simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
   simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
-   *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
-   *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
   simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
   simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
   simdjson_inline simdjson_result<bool> is_string() noexcept;
 
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
   simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
   simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
   simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
+  simdjson_inline simdjson_result<number> get_number() noexcept;
   simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
-
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
-   */
   simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
-   *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
   simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-  /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-protected:
-  /**
-   * Consumes the document.
-   */
-  simdjson_inline error_code consume() noexcept;
-
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
-
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
-
-  friend class array_iterator;
-  friend class value;
-  friend class ondemand::parser;
-  friend class object;
-  friend class array;
-  friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
+private:
+  document *doc{nullptr};
 };
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
+namespace simdjson {
 
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
+template<>
+struct simdjson_result<ppc64::ondemand::document> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::document> {
 public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result(ppc64::ondemand::document &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
+
+  simdjson_inline simdjson_result<ppc64::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::object> get_object() & noexcept;
   simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
   simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
   simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
@@ -84037,149 +81382,9 @@ class document_reference {
   template <typename string_type>
   simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
   simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> get_raw_json_string() noexcept;
   simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-private:
-  document *doc{nullptr};
-};
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<ppc64::ondemand::document> : public ppc64::implementation_simdjson_result_base<ppc64::ondemand::document> {
-public:
-  simdjson_inline simdjson_result(ppc64::ondemand::document &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<ppc64::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<ppc64::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<ppc64::ondemand::value> get_value() noexcept;
   simdjson_inline simdjson_result<bool> is_null() noexcept;
 
   template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
@@ -86134,8 +83339,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::g
 }
 simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::value>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
 template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::value>::get<ppc64::ondemand::value>(ppc64::ondemand::value &out) noexcept {
@@ -86224,6 +83428,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::value>::operator bool() noexcep
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
+#endif
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::value>::raw_json_token() noexcept {
   if (error()) { return error(); }
@@ -86664,27 +83869,27 @@ simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.find_field_unordered(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.find_field_unordered(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first[key];
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first[key];
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(const char *key) & noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.find_field(key);
 }
 simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
@@ -86741,12 +83946,11 @@ simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>
 }
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
 simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
 template<typename T>
@@ -86826,7 +84030,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::document>::operator T() noexcep
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -86865,7 +84069,7 @@ simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::onde
 
 simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
 simdjson_inline bool simdjson_result<ppc64::ondemand::document>::at_end() const noexcept {
@@ -86881,12 +84085,12 @@ simdjson_inline int32_t simdjson_result<ppc64::ondemand::document>::current_dept
 
 simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.raw_json_token();
 }
 
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.at_pointer(json_pointer);
 }
 
 simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_path(std::string_view json_path) noexcept {
@@ -87349,1414 +84553,1450 @@ simdjson_inline document_stream::document_stream(
   if(worker.get() == nullptr) {
     error = MEMALLOC;
   }
+#endif
 }
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
 
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
-  }
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
 
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+}
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
 
 simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
   return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
-}
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
-}
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
-}
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
-}
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
-}
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
-}
-
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
-
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
-
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-#endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
+
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
   }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
-}
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
-}
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
-}
-
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
   }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
+
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
   }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
+}
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
 }
 
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+}
+
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::document>::simdjson_result(
-  ppc64::ondemand::document &&value
+simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document>(
-      std::forward<ppc64::ondemand::document>(value)
-    )
+    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(error)
 {
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
+  ppc64::ondemand::document_stream &&value
 ) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document>(
-      error
+    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(
+      std::forward<ppc64::ondemand::document_stream>(value)
     )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::document>(first).get<T>();
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/field-inl.h for ppc64: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::document>(first).get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-template<> simdjson_inline simdjson_result<ppc64::ondemand::document> simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<ppc64::ondemand::document> simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::document>(first);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
-template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>(ppc64::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<ppc64::ondemand::document>::get<ppc64::ondemand::document>(ppc64::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<ppc64::ondemand::document>(first);
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
   return SUCCESS;
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
 
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_inline bool simdjson_result<ppc64::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
+namespace simdjson {
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, ppc64::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
+  ppc64::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::field>(
+      std::forward<ppc64::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document>::operator ppc64::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<ppc64::ondemand::field>(error)
+{
 }
-#endif
 
-
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document>::current_location() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.key();
 }
 
-simdjson_inline bool simdjson_result<ppc64::ondemand::document>::at_end() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.at_end();
+  return first.key_raw_json_token();
 }
 
-
-simdjson_inline int32_t simdjson_result<ppc64::ondemand::document>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.escaped_key();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<ppc64::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document>::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return std::move(first.value());
 }
 
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
+}
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
+}
 
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
+}
 
-namespace simdjson {
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::simdjson_result(ppc64::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<ppc64::ondemand::document_reference>(std::forward<ppc64::ondemand::document_reference>(value), error) {}
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
 
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
+}
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<ppc64::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array_iterator> simdjson_result<ppc64::ondemand::document_reference>::end() & noexcept {
-  return {};
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::array> simdjson_result<ppc64::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
-simdjson_inline simdjson_result<ppc64::ondemand::object> simdjson_result<ppc64::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<ppc64::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<ppc64::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
-simdjson_inline simdjson_result<double> simdjson_result<ppc64::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<ppc64::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::json_type> simdjson_result<ppc64::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-template <>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-template <>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::document_reference>::get(ppc64::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<ppc64::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
-simdjson_inline simdjson_result<ppc64::number_type> simdjson_result<ppc64::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::number> simdjson_result<ppc64::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, ppc64::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, ppc64::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(std::forward<ppc64::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/json_type-inl.h for ppc64: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
+
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+#endif
+
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
-simdjson_inline simdjson_result<ppc64::ondemand::document_reference>::operator ppc64::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
   }
-  return first.at_path(json_path);
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
+}
+
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
+}
+
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
+}
+
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
+}
+
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
+} // namespace ondemand
+} // namespace ppc64
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/document_stream-inl.h for ppc64: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(ppc64::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(std::forward<ppc64::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/logger-inl.h for ppc64: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
+#include <memory>
+#include <cstring>
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
+namespace logger {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
-
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
 }
 
-
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
+static inline log_level log_threshold()
 {
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
+static inline bool should_log(log_level level)
 {
+  return level >= log_threshold();
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
+}
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
+}
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+}
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
   }
-  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+}
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
-}
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
-}
-
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
-}
-
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
-}
-
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
-}
-
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
           }
-          return std::string_view(start, svlen);
         }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
     }
-    cur_struct_index++;
-  }
-
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
-  }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
-}
-
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
-}
-
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
-
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
   }
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
-}
-
-#endif // SIMDJSON_THREADS_ENABLED
-
+} // namespace logger
 } // namespace ondemand
 } // namespace ppc64
 } // namespace simdjson
 
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(error)
-{
-}
-simdjson_inline simdjson_result<ppc64::ondemand::document_stream>::simdjson_result(
-  ppc64::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::document_stream>(
-      std::forward<ppc64::ondemand::document_stream>(value)
-    )
-{
-}
-
-}
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/field-inl.h for ppc64: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/object-inl.h for ppc64: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
+}
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
+}
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
 
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
 } // namespace ondemand
@@ -88765,486 +86005,412 @@ simdjson_inline value field::value() && noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
-  ppc64::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::field>(
-      std::forward<ppc64::ondemand::field>(value)
-    )
-{
+simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(ppc64::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::object>(std::forward<ppc64::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline simdjson_result<ppc64::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<ppc64::ondemand::field>(error)
-{
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
 }
-
-simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string> simdjson_result<ppc64::ondemand::field>::key() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::key_raw_json_token() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return std::forward<ppc64::ondemand::object>(first).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::object>(first)[key];
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<ppc64::ondemand::object>(first).find_field(key);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::escaped_key() noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.reset();
 }
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<ppc64::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.is_empty();
 }
 
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::field>::value() noexcept {
+simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.count_fields();
 }
 
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
+//
+// object_iterator
+//
+
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
+
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
+
+} // namespace ondemand
+} // namespace ppc64
+} // namespace simdjson
 
+namespace simdjson {
+
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
+  ppc64::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
 {
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+  first.iter.assert_is_valid();
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
+{
 }
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
-  }
-  return count == 0;
+simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
 
+} // namespace simdjson
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
-  }
+namespace simdjson {
+namespace ppc64 {
+namespace ondemand {
 
-  return report_error(TAPE_ERROR, "not enough close braces");
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+  }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
-}
+  json.remove_utf8_bom();
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
-}
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
-  return reinterpret_cast<const char *>(token.peek());
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
+  json.remove_utf8_bom();
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
-}
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
-}
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
   return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
-}
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
-}
-
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
-  }
-  return TAPE_ERROR;
-}
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
-}
-
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
-}
-
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
-  }
-  return true;
 }
 
 } // namespace ondemand
@@ -89253,118 +86419,195 @@ simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const ui
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(ppc64::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(std::forward<ppc64::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_iterator>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/json_type-inl.h for ppc64: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for ppc64: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace ppc64 {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
-}
-
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
-}
-#endif
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
-}
 
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
 } // namespace ondemand
@@ -89373,477 +86616,343 @@ simdjson_inline void number::skip_double() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(ppc64::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(std::forward<ppc64::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(ppc64::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(std::forward<ppc64::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::raw_json_string>(error) {}
 
+simdjson_inline simdjson_result<const char *> simdjson_result<ppc64::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
+}
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
+}
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::raw_json_string>::unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
+}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/logger-inl.h for ppc64: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/serialization-inl.h for ppc64: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
 
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
+
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace ppc64::ondemand;
+  ppc64::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      ppc64::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      ppc64::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+inline simdjson_result<std::string_view> to_json_string(ppc64::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<ppc64::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+namespace simdjson { namespace ppc64 { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
-
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::ppc64::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
   }
 }
+#endif
 
-} // namespace logger
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::ppc64::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::ppc64::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
+}
+#endif
+}}} // namespace simdjson::ppc64::ondemand
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/object-inl.h for ppc64: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
-
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
-
-
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
-  }
-  if(r[pos] != '"') { return false; }
-  return true;
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
 
-simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_object().error() );
-  return object(iter);
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.start_root_object().error() );
-  return object(iter);
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-simdjson_inline error_code object::consume() noexcept {
-  if(iter.is_at_key()) {
-    /**
-     * whenever you are pointing at a key, calling skip_child() is
-     * unsafe because you will hit a string and you will assume that
-     * it is string value, and this mistake will lead you to make bad
-     * depth computation.
-     */
-    /**
-     * We want to 'consume' the key. We could really
-     * just do _json_iter->return_current_and_advance(); at this
-     * point, but, for clarity, we will use the high-level API to
-     * eat the key. We assume that the compiler optimizes away
-     * most of the work.
-     */
-    simdjson_unused raw_json_string actual_key;
-    auto error = iter.field_key().get(actual_key);
-    if (error) { iter.abandon(); return error; };
-    // Let us move to the value while we are at it.
-    if ((error = iter.field_value())) { iter.abandon(); return error; }
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-
-simdjson_inline object object::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
+}
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
 } // namespace ondemand
@@ -89852,465 +86961,50 @@ simdjson_inline simdjson_result<bool> object::reset() & noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(ppc64::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::object>(std::forward<ppc64::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> simdjson_result<ppc64::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first)[key];
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<ppc64::ondemand::object>(first).find_field(key);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::value> simdjson_result<ppc64::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
-
-inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
-}
-
-inline simdjson_result<bool> simdjson_result<ppc64::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
-
-simdjson_inline  simdjson_result<size_t> simdjson_result<ppc64::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
+simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(ppc64::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(std::forward<ppc64::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<ppc64::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<ppc64::ondemand::token_iterator>(error) {}
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<ppc64::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace ppc64 {
 namespace ondemand {
 
-//
-// object_iterator
-//
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
+{
+}
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
+}
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
-}
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
-}
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(
-  ppc64::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>(std::forward<ppc64::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<ppc64::ondemand::object_iterator>({}, error)
-{
-}
-
-simdjson_inline simdjson_result<ppc64::ondemand::field> simdjson_result<ppc64::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator==(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<ppc64::ondemand::object_iterator>::operator!=(const simdjson_result<ppc64::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-// Checks for ']' and ','
-simdjson_inline simdjson_result<ppc64::ondemand::object_iterator> &simdjson_result<ppc64::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
-}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/parser-inl.h for ppc64: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
-}
-
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
-#endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
-  } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
-  }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
-  return SUCCESS;
-}
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
-}
-
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
-
-  json.remove_utf8_bom();
-
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
-
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
-}
-
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
-}
-
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
-}
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
-}
-
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
-}
-
-} // namespace ondemand
-} // namespace ppc64
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(ppc64::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(std::forward<ppc64::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<ppc64::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<ppc64::ondemand::parser>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for ppc64 */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for ppc64: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-
-namespace ppc64 {
-namespace ondemand {
-
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
@@ -90387,8 +87081,6 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_n
     default:
       return report_error(TAPE_ERROR, "Missing comma between object fields");
   }
-  if(r[pos] != '"') { return false; }
-  return true;
 }
 
 simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
@@ -95962,25 +92654,12 @@ class document {
   /**
    * Cast this JSON value to an array.
    *
-   * ### std::string references
-   *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
-   *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
-   *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
-   *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() & noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
    * @returns An object that can be used to look up or iterate fields.
    * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
@@ -96205,13 +92884,43 @@ class document {
    *
    * @returns true if the number if negative.
    */
-  bool threaded{true};
-  #else
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * @returns true if the number if negative.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
   /**
    * Attempt to parse an ondemand::number. An ondemand::number may
    * contain an integer value or a floating-point value, the simdjson
@@ -96281,19 +92990,7 @@ class document {
   inline bool is_alive() noexcept;
 
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
-   *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * Returns the current location in the document if in bounds.
    */
   inline simdjson_result<const char *> current_location() const noexcept;
 
@@ -96725,11 +93422,16 @@ struct simdjson_result<westmere::ondemand::document_reference> : public westmere
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
 /* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
 
 namespace simdjson {
 namespace westmere {
@@ -96939,73 +93641,19 @@ class document_stream {
    * @param len is the length of the raw byte buffer in bytes
    * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
    */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+  simdjson_inline document_stream(
+    ondemand::parser &parser,
+    const uint8_t *buf,
+    size_t len,
+    size_t batch_size,
+    bool allow_comma_separated
+  ) noexcept;
 
   /**
    * Parse the first document in the buffer. Used by begin(), to handle allocation and
    * initialization.
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
+  inline void start() noexcept;
 
   /**
    * Parse the next document found in the buffer previously given to document_stream.
@@ -97167,16 +93815,10 @@ class field : public std::pair<raw_json_string, value> {
    */
   simdjson_inline raw_json_string key() const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
    */
   simdjson_inline std::string_view key_raw_json_token() const noexcept;
   /**
@@ -97339,171 +93981,7 @@ class object {
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-
-  /**
-   * Checks whether the document is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the document is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
-   */
-  inline bool is_alive() noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
-   */
-  inline bool at_end() const noexcept;
-
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
   /**
    * Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -97619,148 +94097,6 @@ class object {
   friend struct simdjson_result<object>;
 };
 
-
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-private:
-  document *doc{nullptr};
-};
 } // namespace ondemand
 } // namespace westmere
 } // namespace simdjson
@@ -97777,10 +94113,7 @@ struct simdjson_result<westmere::ondemand::object> : public westmere::implementa
   simdjson_inline simdjson_result<westmere::ondemand::object_iterator> begin() noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::object_iterator> end() noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
   simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
@@ -97864,64 +94197,9 @@ struct simdjson_result<westmere::ondemand::object_iterator> : public westmere::i
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
 
-  simdjson_inline simdjson_result<westmere::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator westmere::ondemand::array() & noexcept(false);
-  simdjson_inline operator westmere::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator westmere::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator westmere::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<westmere::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<westmere::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<westmere::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  //
+  // Iterator interface
+  //
 
   // Reads key and value, yielding them to the user.
   simdjson_inline simdjson_result<westmere::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
@@ -98754,10 +95032,74 @@ simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number()
   return iter.get_number();
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
+
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
+
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
+
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
 simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
@@ -98992,193 +95334,16 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::onde
   return first.raw_json_token();
 }
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for westmere: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for westmere */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-#include <limits>
-
-namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
-
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
-
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
-
-  westmere::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
-}
-
-
-
-/**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
- *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
- *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
-
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
-  }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  if (!out) {
-    out.emplace();
-  }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for westmere */
-
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for westmere: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
 simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
   if (error()) { return error(); }
   return first.current_depth();
@@ -99202,232 +95367,347 @@ simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westm
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for westmere */
+/* including simdjson/generic/ondemand/document-inl.h for westmere: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
 {
+  logger::log_start_value(iter, "document");
 }
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
+
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
 }
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
+
+inline void document::rewind() noexcept {
+  iter.rewind();
 }
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
 }
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
+
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
 }
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
+
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
+}
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
+}
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
+}
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
+}
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
+}
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
     return get_object();
   } else {
-    return object::resume(iter);
+    return object::resume(resume_value_iterator());
   }
 }
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
 }
 
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
   auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
   return answer;
 }
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
   auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
   return answer;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
   auto a = get_array();
   return a.at(index);
 }
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
   return start_or_resume_object().find_field(key);
 }
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
   return start_or_resume_object()[key];
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
   return start_or_resume_object()[key];
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
   if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
+
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
+
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
+  json_type this_type;
+  auto error = type().get(this_type);
+  if(error) { return error; }
+  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+}
+
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
+  json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return (this_type == json_type::string);
 }
 
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t) {
@@ -99446,1171 +95726,1026 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
-  westmere::ondemand::value &&value
+simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
+  westmere::ondemand::document &&value
 ) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(
-      std::forward<westmere::ondemand::value>(value)
+    implementation_simdjson_result_base<westmere::ondemand::document>(
+      std::forward<westmere::ondemand::document>(value)
     )
 {
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
+simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
   error_code error
 ) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(error)
+    implementation_simdjson_result_base<westmere::ondemand::document>(
+      error
+    )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::rewind() noexcept {
   if (error()) { return error(); }
-  return {};
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.begin();
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
+template<typename T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document>(first).get<T>(out);
+}
 
-template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
+template<> simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<westmere::ondemand::document>(first);
+}
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) && noexcept {
+  if (error()) { return error(); }
+  out = std::forward<westmere::ondemand::document>(first);
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<westmere::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
+template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
+simdjson_inline bool simdjson_result<westmere::ondemand::document>::at_end() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.at_end();
 }
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
+
+simdjson_inline int32_t simdjson_result<westmere::ondemand::document>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/value-inl.h for westmere: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
+
+
+namespace simdjson {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::simdjson_result(westmere::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<westmere::ondemand::document_reference>(std::forward<westmere::ondemand::document_reference>(value), error) {}
+
+
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
+simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
+simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
+simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
+simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
 }
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
+simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
 }
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
-  westmere::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(
-      std::forward<westmere::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<westmere::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document_reference>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>(westmere::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<westmere::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>();
+}
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-
-template<> simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::get<westmere::ondemand::value>() noexcept  {
+template <class T>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<westmere::ondemand::document_reference>(first).get<T>(out);
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::value>::type() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document_reference>::type() noexcept {
   if (error()) { return error(); }
   return first.type();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_scalar() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_scalar() noexcept {
   if (error()) { return error(); }
   return first.is_scalar();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_string() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_negative() noexcept {
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+template <>
+simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
+}
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::value>::is_integer() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::value>::get_number_type() noexcept {
+simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document_reference>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::value>::get_number() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document_reference>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator T() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, westmere::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, westmere::ondemand::document>::value == false, "You should not call get<T> when T is a document");
   if (error()) { throw simdjson_error(error()); }
   return first.get<T>();
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator westmere::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-#endif
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::value() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
+#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::value>::current_location() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document_reference>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<westmere::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
   if (error()) {
-    return error();
+      return error();
   }
   return first.at_path(json_path);
 }
 
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for westmere */
-/* including simdjson/generic/ondemand/document-inl.h for westmere: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for westmere */
+/* including simdjson/generic/ondemand/document_stream-inl.h for westmere: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
-}
+#include <algorithm>
+#include <stdexcept>
 
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
-{
-  logger::log_start_value(iter, "document");
-}
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-inline void document::rewind() noexcept {
-  iter.rewind();
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
-}
 
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
-}
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
-}
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
-}
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
-    return get_object();
-  } else {
-    return object::resume(resume_value_iterator());
-  }
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
 
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
   }
+#endif
 }
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
-}
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
-}
-
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
 
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
-}
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
+
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
+
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
 }
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
+
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
+
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
+
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
+
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
+
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
+
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
 }
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
+}
 
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
 
-#endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
+  }
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
+
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
   }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
 }
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
-}
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
-}
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
+
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
+  }
 }
 
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
+#endif // SIMDJSON_THREADS_ENABLED
 
 } // namespace ondemand
 } // namespace westmere
@@ -100618,1754 +96753,1563 @@ simdjson_inline simdjson_result<value> document::at_path(std::string_view json_p
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
-  westmere::ondemand::document &&value
+simdjson_inline simdjson_result<westmere::ondemand::document_stream>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document>(
-      std::forward<westmere::ondemand::document>(value)
-    )
+    implementation_simdjson_result_base<westmere::ondemand::document_stream>(error)
 {
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<westmere::ondemand::document_stream>::simdjson_result(
+  westmere::ondemand::document_stream &&value
 ) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document>(
-      error
+    implementation_simdjson_result_base<westmere::ondemand::document_stream>(
+      std::forward<westmere::ondemand::document_stream>(value)
     )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first).get<T>();
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for westmere */
+/* including simdjson/generic/ondemand/field-inl.h for westmere: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first).get<T>(out);
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
 
-template<> simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<westmere::ondemand::document>(first);
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
   return SUCCESS;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
 
-simdjson_inline bool simdjson_result<westmere::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
+namespace simdjson {
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<westmere::ondemand::field>::simdjson_result(
+  westmere::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::field>(
+      std::forward<westmere::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<westmere::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<westmere::ondemand::field>(error)
+{
 }
-#endif
 
-
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document>::current_location() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  return first.key();
 }
 
-simdjson_inline bool simdjson_result<westmere::ondemand::document>::at_end() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.at_end();
+  return first.key_raw_json_token();
 }
 
-
-simdjson_inline int32_t simdjson_result<westmere::ondemand::document>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.escaped_key();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::raw_json_token() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first).get<T>();
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<westmere::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return first.at_path(json_path);
+  return std::move(first.value());
 }
 
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for westmere */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
+}
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
+}
 
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-namespace simdjson {
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::simdjson_result(westmere::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<westmere::ondemand::document_reference>(std::forward<westmere::ondemand::document_reference>(value), error) {}
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
+}
 
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
 
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
-template <class T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
 }
-template <>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-template <>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, westmere::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, westmere::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
+
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
   }
-  return first.at_path(json_path);
+  return true;
 }
 
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for westmere */
-/* including simdjson/generic/ondemand/document_stream-inl.h for westmere: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::json_iterator>::simdjson_result(westmere::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::json_iterator>(std::forward<westmere::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/json_type-inl.h for westmere: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
+#endif
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
 
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
-}
-template<typename T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first).get<T>(out);
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-template<> simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<westmere::ondemand::document> simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<westmere::ondemand::document>::get<westmere::ondemand::document>(westmere::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<westmere::ondemand::document>(first);
-  return SUCCESS;
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline bool simdjson_result<westmere::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::json_type>::simdjson_result(westmere::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::json_type>(std::forward<westmere::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for westmere */
+/* including simdjson/generic/ondemand/logger-inl.h for westmere: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <memory>
+#include <cstring>
+
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
+namespace logger {
+
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
+  }
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, westmere::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document>::operator westmere::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
-#endif
 
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline bool simdjson_result<westmere::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
+}
 
-simdjson_inline int32_t simdjson_result<westmere::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
+
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
 }
 
+} // namespace logger
+} // namespace ondemand
+} // namespace westmere
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for westmere */
+/* including simdjson/generic/ondemand/object-inl.h for westmere: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-
-
-namespace simdjson {
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::simdjson_result(westmere::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<westmere::ondemand::document_reference>(std::forward<westmere::ondemand::document_reference>(value), error) {}
-
-
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<westmere::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<westmere::ondemand::array_iterator> simdjson_result<westmere::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<westmere::ondemand::array> simdjson_result<westmere::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<westmere::ondemand::object> simdjson_result<westmere::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<westmere::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<westmere::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<double> simdjson_result<westmere::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<westmere::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
-simdjson_inline simdjson_result<westmere::ondemand::json_type> simdjson_result<westmere::ondemand::document_reference>::type() noexcept {
+
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<westmere::ondemand::object>::simdjson_result(westmere::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::object>(std::forward<westmere::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> simdjson_result<westmere::ondemand::object>::begin() noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return first.begin();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_scalar() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> simdjson_result<westmere::ondemand::object>::end() noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  return first.end();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_string() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.is_string();
+  return first.find_field_unordered(key);
 }
-template <>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) & noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return std::forward<westmere::ondemand::object>(first).find_field_unordered(key);
 }
-template <>
-simdjson_inline error_code simdjson_result<westmere::ondemand::document_reference>::get(westmere::ondemand::document_reference &out) && noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first[key];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_negative() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::operator[](std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.is_negative();
+  return std::forward<westmere::ondemand::object>(first)[key];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<westmere::ondemand::document_reference>::is_integer() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.is_integer();
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<westmere::number_type> simdjson_result<westmere::ondemand::document_reference>::get_number_type() noexcept {
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_number_type();
+  return std::forward<westmere::ondemand::object>(first).find_field(key);
 }
-simdjson_inline simdjson_result<westmere::ondemand::number> simdjson_result<westmere::ondemand::document_reference>::get_number() noexcept {
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, westmere::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, westmere::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_reference>::operator westmere::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::document_reference>::current_location() noexcept {
+inline simdjson_result<bool> simdjson_result<westmere::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.reset();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::document_reference>::raw_json_token() noexcept {
+inline simdjson_result<bool> simdjson_result<westmere::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.is_empty();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.count_fields();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for westmere */
-/* including simdjson/generic/ondemand/document_stream-inl.h for westmere: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for westmere */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
+//
+// object_iterator
+//
 
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
+}
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
-#endif  // SIMDJSON_THREADS_ENABLED
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
-}
+namespace simdjson {
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
+  westmere::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
 {
+  first.iter.assert_is_valid();
 }
-
-simdjson_inline document_stream::~document_stream() noexcept
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
 {
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
-}
-
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
-}
-
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
 }
-
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
-
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
+// Checks for ']' and ','
+simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
   return *this;
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
+} // namespace simdjson
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+namespace simdjson {
+namespace westmere {
+namespace ondemand {
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
-}
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-}
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+  json.remove_utf8_bom();
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
 
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
+  }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
+}
 
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
+}
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
+}
 
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-namespace simdjson {
+  json.remove_utf8_bom();
 
-simdjson_inline simdjson_result<westmere::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document_stream>(error)
-{
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
-simdjson_inline simdjson_result<westmere::ondemand::document_stream>::simdjson_result(
-  westmere::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::document_stream>(
-      std::forward<westmere::ondemand::document_stream>(value)
-    )
-{
-}
-
-}
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for westmere */
-/* including simdjson/generic/ondemand/field-inl.h for westmere: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
 }
-
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
-
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
 }
-
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
 }
-
-
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
+  }
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
 } // namespace ondemand
@@ -102374,511 +98318,468 @@ simdjson_inline value field::value() && noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::field>::simdjson_result(
-  westmere::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::field>(
-      std::forward<westmere::ondemand::field>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<westmere::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<westmere::ondemand::field>(error)
-{
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::raw_json_string> simdjson_result<westmere::ondemand::field>::key() noexcept {
-  if (error()) { return error(); }
-  return first.key();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::key_raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.key_raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::escaped_key() noexcept {
-  if (error()) { return error(); }
-  return first.escaped_key();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<westmere::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
-}
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<westmere::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
-}
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::field>::value() noexcept {
-  if (error()) { return error(); }
-  return std::move(first.value());
-}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for westmere */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for westmere */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for westmere: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace westmere {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
-}
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
-}
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
-
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
-}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
-}
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
     }
+    pos++;
   }
-  return count == 0;
+  return true;
 }
 
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+}
 
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
   }
+  if(r[pos] != '"') { return false; }
+  return true;
+}
 
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
     }
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
-}
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
-}
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
     }
+    out << *s;
+    s++;
   }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
-  }
-  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
+} // namespace ondemand
+} // namespace westmere
+} // namespace simdjson
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
+namespace simdjson {
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(westmere::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(std::forward<westmere::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::raw_json_string>(error) {}
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
+simdjson_inline simdjson_result<const char *> simdjson_result<westmere::ondemand::raw_json_string>::raw() const noexcept {
+  if (error()) { return error(); }
+  return first.raw();
 }
-
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape(iter, allow_replacement);
 }
-
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<westmere::ondemand::raw_json_string>::unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept {
+  if (error()) { return error(); }
+  return first.unescape_wobbly(iter);
 }
+} // namespace simdjson
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for westmere */
+/* including simdjson/generic/ondemand/serialization-inl.h for westmere: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
+
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
+
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace westmere::ondemand;
+  westmere::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
+    {
+      westmere::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
+    }
+    case json_type::object:
+    {
+      westmere::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
+    }
+    default:
+      return trim(x.raw_json_token());
+  }
 }
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
+
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
+inline simdjson_result<std::string_view> to_json_string(westmere::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<westmere::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
+namespace simdjson { namespace westmere { namespace ondemand {
+
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
 #else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
 #else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
 #endif
-  token.set_position(position);
-  _depth = child_depth;
-}
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-  return TAPE_ERROR;
 }
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::westmere::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-
 #endif
 
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::westmere::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::westmere::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
   }
-  return true;
 }
+#endif
+}}} // namespace simdjson::westmere::ondemand
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::json_iterator>::simdjson_result(westmere::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::json_iterator>(std::forward<westmere::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::json_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/json_type-inl.h for westmere: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for westmere */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
@@ -102886,94 +98787,71 @@ namespace simdjson {
 namespace westmere {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-#endif
-
 
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
+}
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
 } // namespace ondemand
@@ -102982,867 +98860,1094 @@ simdjson_inline void number::skip_double() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::json_type>::simdjson_result(westmere::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::json_type>(std::forward<westmere::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(westmere::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(std::forward<westmere::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for westmere */
-/* including simdjson/generic/ondemand/logger-inl.h for westmere: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
 namespace westmere {
 namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
-
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
-}
-
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
-{
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
-}
-
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
-}
 
-static inline log_level log_threshold()
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
 {
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
 }
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
 }
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
-}
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
+
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
+
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
   }
-}
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
-}
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
+
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
   }
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-} // namespace logger
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for westmere */
-/* including simdjson/generic/ondemand/object-inl.h for westmere: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
+}
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
+}
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
+}
 
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
+}
 
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
+}
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
   }
-  return value(iter.child());
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  return true;
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    }
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
     }
-    pos++;
   }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
 }
 
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
   }
-  if(r[pos] != '"') { return false; }
-  return true;
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
 }
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
-
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
-  }
-  return child;
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
 }
-
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
 }
-
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<westmere::ondemand::object>::simdjson_result(westmere::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::object>(std::forward<westmere::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> simdjson_result<westmere::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
 }
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> simdjson_result<westmere::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::object>(first).find_field_unordered(key);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::object>(first)[key];
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
 }
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<westmere::ondemand::object>(first).find_field(key);
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
 }
-
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
+  if(error) { return error; }
+  return num;
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::value> simdjson_result<westmere::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
   }
-  return first.at_path(json_path);
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
 }
 
-inline simdjson_result<bool> simdjson_result<westmere::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+simdjson_inline simdjson_result<westmere::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
 }
-
-inline simdjson_result<bool> simdjson_result<westmere::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
+  if(error) { return error; }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
 }
-
-simdjson_inline  simdjson_result<size_t> simdjson_result<westmere::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
 }
-
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<westmere::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for westmere */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
-
-//
-// object_iterator
-//
-
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
-
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
 }
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
 
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+  return _json_iter->skip_child(depth());
+}
 
-namespace simdjson {
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
+}
 
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(
-  westmere::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>(std::forward<westmere::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
 }
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<westmere::ondemand::object_iterator>({}, error)
-{
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
 }
 
-simdjson_inline simdjson_result<westmere::ondemand::field> simdjson_result<westmere::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator==(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<westmere::ondemand::object_iterator>::operator!=(const simdjson_result<westmere::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<westmere::ondemand::object_iterator> &simdjson_result<westmere::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
+}
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
+}
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
+}
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
+}
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
 }
 
-} // namespace simdjson
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
+}
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
+}
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/parser-inl.h for westmere: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
+}
 
-namespace simdjson {
-namespace westmere {
-namespace ondemand {
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
   } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
   }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
+
+
   return SUCCESS;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_root();
+  return _json_iter->peek();
+}
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+  assert_at_non_root_start();
+  return _json_iter->peek();
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  json.remove_utf8_bom();
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
+  }
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
 }
 
 } // namespace ondemand
@@ -103851,2896 +99956,1799 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(westmere::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(std::forward<westmere::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(westmere::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(std::forward<westmere::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for westmere */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for westmere: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
 
+
+/* end file simdjson/generic/ondemand/amalgamated.h for westmere */
+/* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */
+/* begin file simdjson/westmere/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
+SIMDJSON_UNTARGET_REGION
+#endif
+
+/* undefining SIMDJSON_IMPLEMENTATION from "westmere" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/westmere/end.h */
+
+#endif // SIMDJSON_WESTMERE_IMPLEMENTATION_H
+/* end file simdjson/westmere/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
+/* including simdjson/lsx/ondemand.h: #include "simdjson/lsx/ondemand.h" */
+/* begin file simdjson/lsx/ondemand.h */
+#ifndef SIMDJSON_LSX_ONDEMAND_H
+#define SIMDJSON_LSX_ONDEMAND_H
+
+/* including simdjson/lsx/begin.h: #include "simdjson/lsx/begin.h" */
+/* begin file simdjson/lsx/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "lsx" */
+#define SIMDJSON_IMPLEMENTATION lsx
+/* including simdjson/lsx/base.h: #include "simdjson/lsx/base.h" */
+/* begin file simdjson/lsx/base.h */
+#ifndef SIMDJSON_LSX_BASE_H
+#define SIMDJSON_LSX_BASE_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+/**
+ * Implementation for LSX.
+ */
+namespace lsx {
 
-namespace westmere {
-namespace ondemand {
+class implementation;
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
+namespace {
+namespace simd {
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
+} // namespace simd
+} // unnamed namespace
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
+#endif // SIMDJSON_LSX_BASE_H
+/* end file simdjson/lsx/base.h */
+/* including simdjson/lsx/intrinsics.h: #include "simdjson/lsx/intrinsics.h" */
+/* begin file simdjson/lsx/intrinsics.h */
+#ifndef SIMDJSON_LSX_INTRINSICS_H
+#define SIMDJSON_LSX_INTRINSICS_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+// This should be the correct header whether
+// you use visual studio or other compilers.
+#include <lsxintrin.h>
+
+static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch SX");
+
+#endif //  SIMDJSON_LSX_INTRINSICS_H
+/* end file simdjson/lsx/intrinsics.h */
+/* including simdjson/lsx/bitmanipulation.h: #include "simdjson/lsx/bitmanipulation.h" */
+/* begin file simdjson/lsx/bitmanipulation.h */
+#ifndef SIMDJSON_LSX_BITMANIPULATION_H
+#define SIMDJSON_LSX_BITMANIPULATION_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmask.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace {
+
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+  return __builtin_ctzll(input_num);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num-1);
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+  return __builtin_clzll(input_num);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
+/* result might be undefined when input_num is zero */
+simdjson_inline int count_ones(uint64_t input_num) {
+  return __lsx_vpickve2gr_w(__lsx_vpcnt_d(__m128i(v2u64{input_num, 0})), 0);
 }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
-}
+#endif // SIMDJSON_LSX_BITMANIPULATION_H
+/* end file simdjson/lsx/bitmanipulation.h */
+/* including simdjson/lsx/bitmask.h: #include "simdjson/lsx/bitmask.h" */
+/* begin file simdjson/lsx/bitmask.h */
+#ifndef SIMDJSON_LSX_BITMASK_H
+#define SIMDJSON_LSX_BITMASK_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
+namespace simdjson {
+namespace lsx {
+namespace {
+
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
+  bitmask ^= bitmask << 1;
+  bitmask ^= bitmask << 2;
+  bitmask ^= bitmask << 4;
+  bitmask ^= bitmask << 8;
+  bitmask ^= bitmask << 16;
+  bitmask ^= bitmask << 32;
+  return bitmask;
+}
+
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+/* end file simdjson/lsx/bitmask.h */
+/* including simdjson/lsx/numberparsing_defs.h: #include "simdjson/lsx/numberparsing_defs.h" */
+/* begin file simdjson/lsx/numberparsing_defs.h */
+#ifndef SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+#define SIMDJSON_LSX_NUMBERPARSING_DEFS_H
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
+#include <cstring>
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+namespace simdjson {
+namespace lsx {
+namespace numberparsing {
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+// we don't have appropriate instructions, so let us use a scalar function
+// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+/** @private */
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  uint64_t val;
+  std::memcpy(&val, chars, sizeof(uint64_t));
+  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
+  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
+}
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
+  return answer;
+}
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+} // namespace numberparsing
+} // namespace lsx
+} // namespace simdjson
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
 #endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  }
 
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+/* end file simdjson/lsx/numberparsing_defs.h */
+/* including simdjson/lsx/simd.h: #include "simdjson/lsx/simd.h" */
+/* begin file simdjson/lsx/simd.h */
+#ifndef SIMDJSON_LSX_SIMD_H
+#define SIMDJSON_LSX_SIMD_H
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+namespace simdjson {
+namespace lsx {
+namespace {
+namespace simd {
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
+  // Forward-declared so they can be used by splat and friends.
+  template<typename Child>
+  struct base {
+    __m128i value;
 
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+    // Zero constructor
+    simdjson_inline base() : value{__m128i()} {}
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
+    // Conversion from SIMD register
+    simdjson_inline base(const __m128i _value) : value(_value) {}
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+    // Conversion to SIMD register
+    simdjson_inline operator const __m128i&() const { return this->value; }
+    simdjson_inline operator __m128i&() { return this->value; }
+    simdjson_inline operator const v16i8&() const { return (v16i8&)this->value; }
+    simdjson_inline operator v16i8&() { return (v16i8&)this->value; }
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return __lsx_vor_v(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return __lsx_vand_v(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return __lsx_vxor_v(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return __lsx_vandn_v(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
+  // Forward-declared so they can be used by splat and friends.
+  template<typename T>
+  struct simd8;
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
+    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lsx_vseq_b(lhs, rhs); }
 
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
-}
+    static const int SIZE = sizeof(base<simd8<T>>::value);
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
-}
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+      return __lsx_vor_v(__lsx_vbsll_v(*this, N), __lsx_vbsrl_v(prev_chunk, 16 - N));
+    }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
-}
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) {
+      return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
+    }
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
-  return answer;
-}
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  return true;
-}
+    simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
+    simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) { return __lsx_vreplgr2vr_b(_value); }
+    static simdjson_inline simd8<T> zero() { return __lsx_vldi(0); }
+    static simdjson_inline simd8<T> load(const T values[16]) {
+      return __lsx_vld(reinterpret_cast<const __m128i *>(values), 0);
     }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
     }
-  }
-  return SUCCESS;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
 
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
-}
+    // Store to array
+    simdjson_inline void store(T dst[16]) const {
+      return __lsx_vst(*this, reinterpret_cast<__m128i *>(dst), 0);
+    }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lsx_vadd_b(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lsx_vsub_b(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
-}
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
 
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
-  }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return __lsx_vshuf_b(lookup_table, lookup_table, *this);
+    }
 
-simdjson_inline simdjson_result<westmere::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
+    // get written.
+    template<typename L>
+    simdjson_inline void compress(uint16_t mask, L * output) const {
+      using internal::thintable_epi8;
+      using internal::BitsSetTable256mul2;
+      using internal::pshufb_combine_table;
+      // this particular implementation was inspired by haswell
+      // lsx do it in 2 steps, first 8 bytes and then second 8 bytes...
+      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
+      uint8_t mask2 = uint8_t(mask >> 8); // second least significant 8 bits
+      // next line just loads the 64-bit values thintable_epi8[mask1] and
+      // thintable_epi8[mask2] into a 128-bit register.
+      __m128i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808};
+      // this is the version "nearly pruned"
+      __m128i pruned = __lsx_vshuf_b(*this, *this, shufmask);
+      // we still need to put the  pieces back together.
+      // we compute the popcount of the first words:
+      int pop1 = BitsSetTable256mul2[mask1];
+      // then load the corresponding mask
+      __m128i compactmask = __lsx_vldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
+      __m128i answer = __lsx_vshuf_b(pruned, pruned, compactmask);
+      __lsx_vst(answer, reinterpret_cast<uint8_t*>(output), 0);
     }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
+
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
     }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+  };
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t values[16]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) : simd8({
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+      }) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lsx_vmax_b(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lsx_vmin_b(*this, other); }
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lsx_vslt_b(other, *this); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lsx_vslt_b(*this, other); }
+  };
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
-  }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
-  }
-  return result;
-}
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) : simd8(__m128i(v16u8{
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15
+    })) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lsx_vsadd_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lsx_vssub_bu(*this, other); }
 
-  return _json_iter->skip_child(depth());
-}
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lsx_vmax_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lsx_vmin_bu(other, *this); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
 
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
-}
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+    simdjson_inline bool is_ascii() const { return 0 == __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
+    simdjson_inline bool bits_not_set_anywhere() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
+      return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(__lsx_vand_v(*this, bits)), 0);
+    }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lsx_vsrli_b(*this, N)); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); }
+  };
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
-}
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
-}
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
-}
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      uint16_t mask1 = uint16_t(mask);
+      uint16_t mask2 = uint16_t(mask >> 16);
+      uint16_t mask3 = uint16_t(mask >> 32);
+      uint16_t mask4 = uint16_t(mask >> 48);
+      __m128i zcnt = __lsx_vpcnt_h(__m128i(v2u64{~mask, 0}));
+      uint64_t zcnt1 = __lsx_vpickve2gr_hu(zcnt, 0);
+      uint64_t zcnt2 = __lsx_vpickve2gr_hu(zcnt, 1);
+      uint64_t zcnt3 = __lsx_vpickve2gr_hu(zcnt, 2);
+      uint64_t zcnt4 = __lsx_vpickve2gr_hu(zcnt, 3);
+      uint8_t *voutput = reinterpret_cast<uint8_t*>(output);
+      // There should be a critical value which processes in scaler is faster.
+      if (zcnt1)
+        this->chunks[0].compress(mask1, reinterpret_cast<T*>(voutput));
+      voutput += zcnt1;
+      if (zcnt2)
+        this->chunks[1].compress(mask2, reinterpret_cast<T*>(voutput));
+      voutput += zcnt2;
+      if (zcnt3)
+        this->chunks[2].compress(mask3, reinterpret_cast<T*>(voutput));
+      voutput += zcnt3;
+      if (zcnt4)
+        this->chunks[3].compress(mask4, reinterpret_cast<T*>(voutput));
+      voutput += zcnt4;
+      return reinterpret_cast<uint64_t>(voutput) - reinterpret_cast<uint64_t>(output);
+    }
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
-}
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
+      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
+      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
+    }
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
-}
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
-}
+    simdjson_inline uint64_t to_bitmask() const {
+      __m128i mask1 = __lsx_vmskltz_b(this->chunks[0]);
+      __m128i mask2 = __lsx_vmskltz_b(this->chunks[1]);
+      __m128i mask3 = __lsx_vmskltz_b(this->chunks[2]);
+      __m128i mask4 = __lsx_vmskltz_b(this->chunks[3]);
+      mask1 = __lsx_vilvl_h(mask2, mask1);
+      mask2 = __lsx_vilvl_h(mask4, mask3);
+      return __lsx_vpickve2gr_du(__lsx_vilvl_w(mask2, mask1), 0);
+    }
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+    simdjson_inline simd8<T> reduce_or() const {
+      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
+    }
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] == mask,
+        this->chunks[1] == mask,
+        this->chunks[2] == mask,
+        this->chunks[3] == mask
+      ).to_bitmask();
+    }
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
-}
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return  simd8x64<bool>(
+        this->chunks[0] == other.chunks[0],
+        this->chunks[1] == other.chunks[1],
+        this->chunks[2] == other.chunks[2],
+        this->chunks[3] == other.chunks[3]
+      ).to_bitmask();
+    }
 
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] <= mask,
+        this->chunks[1] <= mask,
+        this->chunks[2] <= mask,
+        this->chunks[3] <= mask
+      ).to_bitmask();
+    }
+  }; // struct simd8x64<T>
 
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+} // namespace simd
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
-  }
+#endif // SIMDJSON_LSX_SIMD_H
+/* end file simdjson/lsx/simd.h */
+/* including simdjson/lsx/stringparsing_defs.h: #include "simdjson/lsx/stringparsing_defs.h" */
+/* begin file simdjson/lsx/stringparsing_defs.h */
+#ifndef SIMDJSON_LSX_STRINGPARSING_DEFS_H
+#define SIMDJSON_LSX_STRINGPARSING_DEFS_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/simd.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  return SUCCESS;
-}
+namespace simdjson {
+namespace lsx {
+namespace {
 
+using namespace simd;
 
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
+public:
+  static constexpr uint32_t BYTES_PROCESSED = 32;
+  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
 
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
+  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
+  simdjson_inline bool has_backslash() { return bs_bits != 0; }
+  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
+  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
 
-  assert_at_non_root_start();
-  return _json_iter->peek();
-}
+  uint32_t bs_bits;
+  uint32_t quote_bits;
+}; // struct backslash_and_quote
 
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
+simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 31 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v0(src);
+  simd8<uint8_t> v1(src + sizeof(v0));
+  v0.store(dst);
+  v1.store(dst + sizeof(v0));
 
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
+  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on LSX; therefore, we
+  // smash them together into a 64-byte mask and get the bitmask from there.
+  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
+  return {
+    uint32_t(bs_and_quote),      // bs_bits
+    uint32_t(bs_and_quote >> 32) // quote_bits
+  };
 }
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
 
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
+} // unnamed namespace
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
-}
+#endif // SIMDJSON_LSX_STRINGPARSING_DEFS_H
+/* end file simdjson/lsx/stringparsing_defs.h */
 
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
-}
+#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
+/* end file simdjson/lsx/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for lsx: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for lsx */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
+#endif
 
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
-}
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for lsx: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+namespace simdjson {
+namespace lsx {
+/**
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
+ */
+namespace ondemand {
 
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
 
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+/** @copydoc simdjson::lsx::number_type */
+using number_type = simdjson::lsx::number_type;
 
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
-}
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
 
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
-}
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
-}
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for lsx */
+/* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for lsx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
+#include <concepts>
+namespace simdjson {
 
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
-
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
-
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
+namespace tag_invoke_fn_ns {
+void tag_invoke();
 
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
   }
-}
+};
+} // namespace tag_invoke_fn_ns
 
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
-}
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
 
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
-}
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
 
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
 
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
 
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
-}
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
 
-} // namespace ondemand
-} // namespace westmere
-} // namespace simdjson
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
 
-namespace simdjson {
 
-simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(westmere::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(std::forward<westmere::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<westmere::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<westmere::ondemand::value_iterator>(error) {}
+struct deserialize_tag;
 
-} // namespace simdjson
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<lsx::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
 
+template <typename T, typename ValT = lsx::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
 
-/* end file simdjson/generic/ondemand/amalgamated.h for westmere */
-/* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */
-/* begin file simdjson/westmere/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/westmere/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+template <typename T, typename ValT = lsx::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-#if !SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
-SIMDJSON_UNTARGET_REGION
-#endif
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
 
-/* undefining SIMDJSON_IMPLEMENTATION from "westmere" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/westmere/end.h */
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = lsx::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
 
-#endif // SIMDJSON_WESTMERE_IMPLEMENTATION_H
-/* end file simdjson/westmere/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
-/* including simdjson/lsx/ondemand.h: #include "simdjson/lsx/ondemand.h" */
-/* begin file simdjson/lsx/ondemand.h */
-#ifndef SIMDJSON_LSX_ONDEMAND_H
-#define SIMDJSON_LSX_ONDEMAND_H
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = lsx::ondemand::value;
+  using document_type = lsx::ondemand::document;
+  using document_reference_type = lsx::ondemand::document_reference;
 
-/* including simdjson/lsx/begin.h: #include "simdjson/lsx/begin.h" */
-/* begin file simdjson/lsx/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "lsx" */
-#define SIMDJSON_IMPLEMENTATION lsx
-/* including simdjson/lsx/base.h: #include "simdjson/lsx/base.h" */
-/* begin file simdjson/lsx/base.h */
-#ifndef SIMDJSON_LSX_BASE_H
-#define SIMDJSON_LSX_BASE_H
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-namespace simdjson {
-/**
- * Implementation for LSX.
- */
-namespace lsx {
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-class implementation;
 
-namespace {
-namespace simd {
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
-} // namespace simd
-} // unnamed namespace
+} deserialize{};
 
-} // namespace lsx
 } // namespace simdjson
 
-#endif // SIMDJSON_LSX_BASE_H
-/* end file simdjson/lsx/base.h */
-/* including simdjson/lsx/intrinsics.h: #include "simdjson/lsx/intrinsics.h" */
-/* begin file simdjson/lsx/intrinsics.h */
-#ifndef SIMDJSON_LSX_INTRINSICS_H
-#define SIMDJSON_LSX_INTRINSICS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-// This should be the correct header whether
-// you use visual studio or other compilers.
-#include <lsxintrin.h>
-
-static_assert(sizeof(__m128i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch SX");
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
 
-#endif //  SIMDJSON_LSX_INTRINSICS_H
-/* end file simdjson/lsx/intrinsics.h */
-/* including simdjson/lsx/bitmanipulation.h: #include "simdjson/lsx/bitmanipulation.h" */
-/* begin file simdjson/lsx/bitmanipulation.h */
-#ifndef SIMDJSON_LSX_BITMANIPULATION_H
-#define SIMDJSON_LSX_BITMANIPULATION_H
+/* end file simdjson/generic/ondemand/deserialize.h for lsx */
+/* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmask.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
-namespace {
+namespace ondemand {
 
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-  return __builtin_ctzll(input_num);
-}
+/**
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
+ *
+ * @private This is not intended for external use.
+ */
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
+  /**
+   * The starting token index for this value
+   */
+  token_position _start_position{};
 
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num-1);
-}
+public:
+  simdjson_inline value_iterator() noexcept = default;
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-  return __builtin_clzll(input_num);
-}
+  /**
+   * Denote that we're starting a document.
+   */
+  simdjson_inline void start_document() noexcept;
 
-/* result might be undefined when input_num is zero */
-simdjson_inline int count_ones(uint64_t input_num) {
-  return __lsx_vpickve2gr_w(__lsx_vpcnt_d(__m128i(v2u64{input_num, 0})), 0);
-}
+  /**
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   *
+   * Optimized for scalars.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
 
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-}
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
 
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Tell whether the iterator is at the start of the value
+   */
+  simdjson_inline bool at_start() const noexcept;
 
-#endif // SIMDJSON_LSX_BITMANIPULATION_H
-/* end file simdjson/lsx/bitmanipulation.h */
-/* including simdjson/lsx/bitmask.h: #include "simdjson/lsx/bitmask.h" */
-/* begin file simdjson/lsx/bitmask.h */
-#ifndef SIMDJSON_LSX_BITMASK_H
-#define SIMDJSON_LSX_BITMASK_H
+  /**
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   */
+  simdjson_inline bool is_open() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Tell whether the value is at an object's first field (just after the {).
+   */
+  simdjson_inline bool at_first_field() const noexcept;
 
-namespace simdjson {
-namespace lsx {
-namespace {
+  /**
+   * Abandon all iteration.
+   */
+  simdjson_inline void abandon() noexcept;
 
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
-  bitmask ^= bitmask << 1;
-  bitmask ^= bitmask << 2;
-  bitmask ^= bitmask << 4;
-  bitmask ^= bitmask << 8;
-  bitmask ^= bitmask << 16;
-  bitmask ^= bitmask << 32;
-  return bitmask;
-}
+  /**
+   * Get the child value as a value_iterator.
+   */
+  simdjson_inline value_iterator child_value() const noexcept;
 
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Get the depth of this value.
+   */
+  simdjson_inline int32_t depth() const noexcept;
 
-#endif
-/* end file simdjson/lsx/bitmask.h */
-/* including simdjson/lsx/numberparsing_defs.h: #include "simdjson/lsx/numberparsing_defs.h" */
-/* begin file simdjson/lsx/numberparsing_defs.h */
-#ifndef SIMDJSON_LSX_NUMBERPARSING_DEFS_H
-#define SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+  /**
+   * Get the JSON type of this value.
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * @addtogroup object Object iteration
+   *
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
+   *
+   * @{
+   */
 
-#include <cstring>
+  /**
+   * Start an object iteration.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  /**
+   * Start an object iteration from the root.
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  /**
+   * Checks whether an object could be started from the root. May be called by start_root_object.
+   *
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  /**
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  /**
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
-namespace simdjson {
-namespace lsx {
-namespace numberparsing {
+  /**
+   * Moves to the next field in an object.
+   *
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
 
-// we don't have appropriate instructions, so let us use a scalar function
-// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
-/** @private */
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  uint64_t val;
-  std::memcpy(&val, chars, sizeof(uint64_t));
-  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
-  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
-  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
-}
+  /**
+   * Get the current field's key.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
 
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
-  return answer;
-}
+  /**
+   * Pass the : in the field and move to its value.
+   */
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
 
-} // namespace numberparsing
-} // namespace lsx
-} // namespace simdjson
+  /**
+   * Find the next field with the given key.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
 
-#ifndef SIMDJSON_SWAR_NUMBER_PARSING
-#if SIMDJSON_IS_BIG_ENDIAN
-#define SIMDJSON_SWAR_NUMBER_PARSING 0
-#else
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-#endif
-#endif
+  /**
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
 
-#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
-/* end file simdjson/lsx/numberparsing_defs.h */
-/* including simdjson/lsx/simd.h: #include "simdjson/lsx/simd.h" */
-/* begin file simdjson/lsx/simd.h */
-#ifndef SIMDJSON_LSX_SIMD_H
-#define SIMDJSON_LSX_SIMD_H
+  /**
+   * Find the field with the given key without regard to order, and *without* unescaping.
+   *
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /** @} */
 
-namespace simdjson {
-namespace lsx {
-namespace {
-namespace simd {
+  /**
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
+   */
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename Child>
-  struct base {
-    __m128i value;
+  /**
+   * Check for an opening [ and start an array iteration.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  /**
+   * Check for an opening [ and start an array iteration while at the root.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  /**
+   * Checks whether an array could be started from the root. May be called by start_root_array.
+   *
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  /**
+   * Start an array iteration, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  /**
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
-    // Zero constructor
-    simdjson_inline base() : value{__m128i()} {}
+  /**
+   * Moves to the next element in an array.
+   *
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
-    // Conversion from SIMD register
-    simdjson_inline base(const __m128i _value) : value(_value) {}
+  /**
+   * Get a child value iterator.
+   */
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
 
-    // Conversion to SIMD register
-    simdjson_inline operator const __m128i&() const { return this->value; }
-    simdjson_inline operator __m128i&() { return this->value; }
-    simdjson_inline operator const v16i8&() const { return (v16i8&)this->value; }
-    simdjson_inline operator v16i8&() { return (v16i8&)this->value; }
+  /** @} */
 
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return __lsx_vor_v(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return __lsx_vand_v(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return __lsx_vxor_v(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return __lsx_vandn_v(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
+  /**
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
+   */
 
-  // Forward-declared so they can be used by splat and friends.
-  template<typename T>
-  struct simd8;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
 
-    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lsx_vseq_b(lhs, rhs); }
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
 
-    static const int SIZE = sizeof(base<simd8<T>>::value);
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-      return __lsx_vor_v(__lsx_vbsll_v(*this, N), __lsx_vbsrl_v(prev_chunk, 16 - N));
-    }
-  };
+  /** @} */
+protected:
+  /**
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  /**
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  /**
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) {
-      return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
-    }
+  /**
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
+   *
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
 
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
 
-    simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
-    simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
+   *
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   */
 
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) { return __lsx_vreplgr2vr_b(_value); }
-    static simdjson_inline simd8<T> zero() { return __lsx_vldi(0); }
-    static simdjson_inline simd8<T> load(const T values[16]) {
-      return __lsx_vld(reinterpret_cast<const __m128i *>(values), 0);
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
 
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m128i _value) : base8<T>(_value) {}
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
 
-    // Store to array
-    simdjson_inline void store(T dst[16]) const {
-      return __lsx_vst(*this, reinterpret_cast<__m128i *>(dst), 0);
-    }
 
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lsx_vadd_b(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lsx_vsub_b(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
 
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
+  /**
+   * Advance to a place expecting a value (increasing depth).
+   *
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
+   */
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
 
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return __lsx_vshuf_b(lookup_table, lookup_table, *this);
-    }
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
 
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
-    // get written.
-    template<typename L>
-    simdjson_inline void compress(uint16_t mask, L * output) const {
-      using internal::thintable_epi8;
-      using internal::BitsSetTable256mul2;
-      using internal::pshufb_combine_table;
-      // this particular implementation was inspired by haswell
-      // lsx do it in 2 steps, first 8 bytes and then second 8 bytes...
-      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
-      uint8_t mask2 = uint8_t(mask >> 8); // second least significant 8 bits
-      // next line just loads the 64-bit values thintable_epi8[mask1] and
-      // thintable_epi8[mask2] into a 128-bit register.
-      __m128i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808};
-      // this is the version "nearly pruned"
-      __m128i pruned = __lsx_vshuf_b(*this, *this, shufmask);
-      // we still need to put the  pieces back together.
-      // we compute the popcount of the first words:
-      int pop1 = BitsSetTable256mul2[mask1];
-      // then load the corresponding mask
-      __m128i compactmask = __lsx_vldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
-      __m128i answer = __lsx_vshuf_b(pruned, pruned, compactmask);
-      __lsx_vst(answer, reinterpret_cast<uint8_t*>(output), 0);
-    }
+  simdjson_inline bool is_at_start() const noexcept;
+  /**
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
+   *
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   */
+  simdjson_inline bool is_at_iterator_start() const noexcept;
 
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
-    }
-  };
+  /**
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
+   *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
+   */
+  simdjson_inline bool is_at_key() const noexcept;
 
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t values[16]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) : simd8({
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-      }) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lsx_vmax_b(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lsx_vmin_b(*this, other); }
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lsx_vslt_b(other, *this); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lsx_vslt_b(*this, other); }
-  };
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
 
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m128i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) : simd8(__m128i(v16u8{
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15
-    })) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
 
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lsx_vsadd_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lsx_vssub_bu(*this, other); }
+  friend class document;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lsx_vmax_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lsx_vmin_bu(other, *this); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
-    simdjson_inline bool is_ascii() const { return 0 == __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
-    simdjson_inline bool bits_not_set_anywhere() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
-      return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(__lsx_vand_v(*this, bits)), 0);
-    }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lsx_vsrli_b(*this, N)); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); }
-  };
+namespace simdjson {
 
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
+template<>
+struct simdjson_result<lsx::ondemand::value_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value_iterator> {
+public:
+  simdjson_inline simdjson_result(lsx::ondemand::value_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
 
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
+} // namespace simdjson
 
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for lsx */
+/* including simdjson/generic/ondemand/value.h for lsx: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      uint16_t mask1 = uint16_t(mask);
-      uint16_t mask2 = uint16_t(mask >> 16);
-      uint16_t mask3 = uint16_t(mask >> 32);
-      uint16_t mask4 = uint16_t(mask >> 48);
-      __m128i zcnt = __lsx_vpcnt_h(__m128i(v2u64{~mask, 0}));
-      uint64_t zcnt1 = __lsx_vpickve2gr_hu(zcnt, 0);
-      uint64_t zcnt2 = __lsx_vpickve2gr_hu(zcnt, 1);
-      uint64_t zcnt3 = __lsx_vpickve2gr_hu(zcnt, 2);
-      uint64_t zcnt4 = __lsx_vpickve2gr_hu(zcnt, 3);
-      uint8_t *voutput = reinterpret_cast<uint8_t*>(output);
-      // There should be a critical value which processes in scaler is faster.
-      if (zcnt1)
-        this->chunks[0].compress(mask1, reinterpret_cast<T*>(voutput));
-      voutput += zcnt1;
-      if (zcnt2)
-        this->chunks[1].compress(mask2, reinterpret_cast<T*>(voutput));
-      voutput += zcnt2;
-      if (zcnt3)
-        this->chunks[2].compress(mask3, reinterpret_cast<T*>(voutput));
-      voutput += zcnt3;
-      if (zcnt4)
-        this->chunks[3].compress(mask4, reinterpret_cast<T*>(voutput));
-      voutput += zcnt4;
-      return reinterpret_cast<uint64_t>(voutput) - reinterpret_cast<uint64_t>(output);
-    }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
-      this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
-      this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
-    }
-
-    simdjson_inline uint64_t to_bitmask() const {
-      __m128i mask1 = __lsx_vmskltz_b(this->chunks[0]);
-      __m128i mask2 = __lsx_vmskltz_b(this->chunks[1]);
-      __m128i mask3 = __lsx_vmskltz_b(this->chunks[2]);
-      __m128i mask4 = __lsx_vmskltz_b(this->chunks[3]);
-      mask1 = __lsx_vilvl_h(mask2, mask1);
-      mask2 = __lsx_vilvl_h(mask4, mask3);
-      return __lsx_vpickve2gr_du(__lsx_vilvl_w(mask2, mask1), 0);
-    }
-
-    simdjson_inline simd8<T> reduce_or() const {
-      return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
-    }
-
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] == mask,
-        this->chunks[1] == mask,
-        this->chunks[2] == mask,
-        this->chunks[3] == mask
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return  simd8x64<bool>(
-        this->chunks[0] == other.chunks[0],
-        this->chunks[1] == other.chunks[1],
-        this->chunks[2] == other.chunks[2],
-        this->chunks[3] == other.chunks[3]
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] <= mask,
-        this->chunks[1] <= mask,
-        this->chunks[2] <= mask,
-        this->chunks[3] <= mask
-      ).to_bitmask();
-    }
-  }; // struct simd8x64<T>
-
-} // namespace simd
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
-
-#endif // SIMDJSON_LSX_SIMD_H
-/* end file simdjson/lsx/simd.h */
-/* including simdjson/lsx/stringparsing_defs.h: #include "simdjson/lsx/stringparsing_defs.h" */
-/* begin file simdjson/lsx/stringparsing_defs.h */
-#ifndef SIMDJSON_LSX_STRINGPARSING_DEFS_H
-#define SIMDJSON_LSX_STRINGPARSING_DEFS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/simd.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace {
-
-using namespace simd;
-
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 32;
-  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
-
-  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
-  simdjson_inline bool has_backslash() { return bs_bits != 0; }
-  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
-  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
-
-  uint32_t bs_bits;
-  uint32_t quote_bits;
-}; // struct backslash_and_quote
-
-simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 31 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v0(src);
-  simd8<uint8_t> v1(src + sizeof(v0));
-  v0.store(dst);
-  v1.store(dst + sizeof(v0));
-
-  // Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on LSX; therefore, we
-  // smash them together into a 64-byte mask and get the bitmask from there.
-  uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
-  return {
-    uint32_t(bs_and_quote),      // bs_bits
-    uint32_t(bs_and_quote >> 32) // quote_bits
-  };
-}
-
-} // unnamed namespace
-} // namespace lsx
-} // namespace simdjson
-
-#endif // SIMDJSON_LSX_STRINGPARSING_DEFS_H
-/* end file simdjson/lsx/stringparsing_defs.h */
-
-#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
-/* end file simdjson/lsx/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for lsx: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for lsx */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
-#endif
-
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for lsx: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
-
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
-
-/** @copydoc simdjson::lsx::number_type */
-using number_type = simdjson::lsx::number_type;
-
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
-
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for lsx */
-/* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for lsx */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+#include <type_traits>
 
-#include <concepts>
 namespace simdjson {
 
-namespace tag_invoke_fn_ns {
-void tag_invoke();
-
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
-
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
-
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
-
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
-
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
-
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
-
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
-
-
-struct deserialize_tag;
-
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<lsx::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
-
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
-
-template <typename T, typename ValT = lsx::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
-
-template <typename T, typename ValT = lsx::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-template <typename T, typename ValT = lsx::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
-
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = lsx::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = lsx::ondemand::value;
-  using document_type = lsx::ondemand::document;
-  using document_reference_type = lsx::ondemand::document_reference;
-
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-
-} deserialize{};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for lsx */
-/* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
 namespace lsx {
 namespace ondemand {
-
 /**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
- *
- * @private This is not intended for external use.
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
  */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
-
+class value {
 public:
-  simdjson_inline value_iterator() noexcept = default;
-
   /**
-   * Denote that we're starting a document.
+   * Create a new invalid value.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline void start_document() noexcept;
+  simdjson_inline value() noexcept = default;
 
   /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
+   * Get this value as the given type.
    *
-   * Optimized for scalars.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
 
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
 
   /**
-   * Tell whether the iterator is at the start of the value
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline bool at_start() const noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline bool is_open() const noexcept;
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
   /**
-   * Tell whether the value is at an object's first field (just after the {).
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline bool at_first_field() const noexcept;
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
   /**
-   * Abandon all iteration.
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline void abandon() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
   /**
-   * Get the child value as a value_iterator.
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline value_iterator child_value() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
   /**
-   * Get the depth of this value.
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline int32_t depth() const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
   /**
-   * Get the JSON type of this value.
+   * Cast this JSON value (inside string) to a signed integer.
    *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
   /**
-   * @addtogroup object Object iteration
-   *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
+   * Cast this JSON value to a double.
    *
-   * @{
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * Start an object iteration.
+   * Cast this JSON value (inside string) to a double
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+
   /**
-   * Start an object iteration from the root.
+   * Cast this JSON value to a string.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
-  /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
-  /**
-   * Start an object iteration after the user has already checked and moved past the {.
+   * Equivalent to get<std::string_view>().
    *
-   * Does not move the iterator unless the object is empty ({}).
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
-  /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
    *
-   * Does not move the iterator unless the object is empty ({}).
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
    *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
 
   /**
-   * Moves to the next field in an object.
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
 
   /**
-   * Get the current field's key.
+   * Cast this JSON value to a "wobbly" string.
+   *
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
-
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
   /**
-   * Pass the : in the field and move to its value.
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
 
   /**
-   * Find the next field with the given key.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * Cast this JSON value to a bool.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
    */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
 
   /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
+#if SIMDJSON_EXCEPTIONS
   /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
-   *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
    *
-   * This means the iterator must be sitting at the next key:
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
    *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  /**
+   * Cast this JSON value to an array.
    *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
-
-  /** @} */
-
+  simdjson_inline operator array() noexcept(false);
   /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
    */
-
+  simdjson_inline operator object() noexcept(false);
   /**
-   * Check for an opening [ and start an array iteration.
+   * Cast this JSON value to an unsigned integer.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  simdjson_inline operator uint64_t() noexcept(false);
   /**
-   * Check for an opening [ and start an array iteration while at the root.
+   * Cast this JSON value to a signed integer.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  simdjson_inline operator int64_t() noexcept(false);
   /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
+   * Cast this JSON value to a double.
    *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  simdjson_inline operator double() noexcept(false);
   /**
-   * Start an array iteration, after the user has already checked and moved past the [.
+   * Cast this JSON value to a string.
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * The string is guaranteed to be valid UTF-8.
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * Equivalent to get<std::string_view>().
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  simdjson_inline operator std::string_view() noexcept(false);
   /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   * Cast this JSON value to a raw_json_string.
    *
-   * Does not move the iterator unless the array is empty ([]).
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
-
+  simdjson_inline operator raw_json_string() noexcept(false);
   /**
-   * Moves to the next element in an array.
-   *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
+   * Cast this JSON value to a bool.
    *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
+  simdjson_inline operator bool() noexcept(false);
+#endif
 
   /**
-   * Get a child value iterator.
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   *
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
-
-  /** @} */
-
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
   /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
-
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
-
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
-
-  /** @} */
-protected:
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
   /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
   /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
-
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
   /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
 
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
 
   /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
-   *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
+   * Look up a field by name on an object, without regard to key order.
    *
-   * ({"globals":{"a":{"shadowable":[}}}})
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
    *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
    *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
-
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
-
-
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
   /**
-   * Advance to a place expecting a value (increasing depth).
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
    *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
-
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
-  simdjson_inline bool is_at_start() const noexcept;
   /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
-
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
   /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
+   * Checks whether the value is a string.
    *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline bool is_at_key() const noexcept;
-
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
-
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
-
-  /** @copydoc error_code json_iterator::position() const noexcept; */
-  simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
-  friend class document;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class field;
-}; // value_iterator
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lsx::ondemand::value_iterator> : public lsx::implementation_simdjson_result_base<lsx::ondemand::value_iterator> {
-public:
-  simdjson_inline simdjson_result(lsx::ondemand::value_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for lsx */
-/* including simdjson/generic/ondemand/value.h for lsx: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <type_traits>
-
-namespace simdjson {
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
-namespace lsx {
-namespace ondemand {
-/**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
- */
-class value {
-public:
   /**
-   * Create a new invalid value.
+   * Checks whether the value is a negative number.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @returns true if the number if negative.
    */
-  simdjson_inline value() noexcept = default;
-
+  simdjson_inline bool is_negative() noexcept;
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
-
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
-
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-
-  /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-
-  /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-#if SIMDJSON_EXCEPTIONS
-  /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() noexcept(false);
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline operator double() noexcept(false);
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
-   */
-  simdjson_inline operator bool() noexcept(false);
-#endif
-
-  /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
-   *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  /**
-   * Checks whether the value is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  /**
-   * Checks whether the value is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
    *
    * @returns true if the number if negative.
    */
@@ -108935,29 +103943,6 @@ class document {
     noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
 #else
     noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
 #endif
   {
     static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
@@ -111423,10 +106408,74 @@ simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number()
   return iter.get_number();
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline std::string_view value::raw_json_token() noexcept {
+  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+}
+
+simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array: {
+      ondemand::array array;
+      SIMDJSON_TRY(get_array().get(array));
+      return array.raw_json();
+    }
+    case json_type::object: {
+      ondemand::object object;
+      SIMDJSON_TRY(get_object().get(object));
+      return object.raw_json();
+    }
+    default:
+      return raw_json_token();
+  }
+}
+
+simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
+  return iter.json_iter().current_location();
+}
+
+simdjson_inline int32_t value::current_depth() const noexcept{
+  return iter.json_iter().depth();
+}
+
+inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
+  if (simdjson_unlikely(json_pointer.empty())) { // can't be
+    return false;
+  }
+  if (simdjson_unlikely(json_pointer[0] != '/')) {
+    return false;
+  }
+  size_t escape = json_pointer.find('~');
+  if (escape == std::string_view::npos) {
+    return true;
+  }
+  if (escape == json_pointer.size() - 1) {
+    return false;
+  }
+  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
+    return false;
+  }
+  return true;
+}
+
+simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
+      if (is_pointer_well_formed(json_pointer)) {
+        return NO_SUCH_FIELD;
+      }
+      return INVALID_JSON_POINTER;
+  }
 }
 
 simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
@@ -111661,193 +106710,16 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand:
   return first.raw_json_token();
 }
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for lsx: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for lsx */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-#include <limits>
-
-namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
-
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
-
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
-
-  lsx::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
-}
-
-
-
-/**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
- *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
- *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
- */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
-
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
-  }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
-
-  if (!out) {
-    out.emplace();
-  }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
+  if (error()) { return error(); }
+  return first.current_location();
 }
 
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for lsx */
-
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for lsx: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
 simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
   if (error()) { return error(); }
   return first.current_depth();
@@ -111871,232 +106743,347 @@ simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondem
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+/* end file simdjson/generic/ondemand/value-inl.h for lsx */
+/* including simdjson/generic/ondemand/document-inl.h for lsx: #include "simdjson/generic/ondemand/document-inl.h" */
+/* begin file simdjson/generic/ondemand/document-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
+simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
+  : iter{std::forward<json_iterator>(_iter)}
 {
+  logger::log_start_value(iter, "document");
 }
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
+
+simdjson_inline document document::start(json_iterator &&iter) noexcept {
+  return document(std::forward<json_iterator>(iter));
 }
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
+
+inline void document::rewind() noexcept {
+  iter.rewind();
 }
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
+inline std::string document::to_debug_string() noexcept {
+  return iter.to_string();
 }
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
+
+inline simdjson_result<const char *> document::current_location() const noexcept {
+  return iter.current_location();
 }
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
+
+inline int32_t document::current_depth() const noexcept {
+  return iter.depth();
+}
+
+inline bool document::at_end() const noexcept {
+  return iter.at_end();
+}
+
+
+inline bool document::is_alive() noexcept {
+  return iter.is_alive();
+}
+simdjson_inline value_iterator document::resume_value_iterator() noexcept {
+  return value_iterator(&iter, 1, iter.root_position());
+}
+simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
+  return resume_value_iterator();
+}
+simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
+  if (iter.at_root()) {
     return get_object();
   } else {
-    return object::resume(iter);
+    return object::resume(resume_value_iterator());
   }
 }
+simdjson_inline simdjson_result<value> document::get_value() noexcept {
+  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
+  // gets called.
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
+  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
+  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  // assert_at_root() serves two purposes: in Debug mode, whether or not
+  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
+  // the document (this will typically be redundant). In release mode, it generates
+  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
+  iter.assert_at_root();
+  switch (*iter.peek()) {
+    case '[': {
+      // The following lines check that the document ends with ].
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_array();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    case '{': {
+      // The following lines would check that the document ends with }.
+      auto value_iterator = get_root_value_iterator();
+      auto error = value_iterator.check_root_object();
+      if(error) { return error; }
+      return value(get_root_value_iterator());
+    }
+    default:
+      // Unfortunately, scalar documents are a special case in simdjson and they cannot
+      // be safely converted to value instances.
+      return SCALAR_DOCUMENT_AS_VALUE;
+  }
 }
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
+simdjson_inline simdjson_result<array> document::get_array() & noexcept {
+  auto value = get_root_value_iterator();
+  return array::start_root(value);
 }
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
+simdjson_inline simdjson_result<object> document::get_object() & noexcept {
+  auto value = get_root_value_iterator();
+  return object::start_root(value);
 }
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
+
+/**
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content. We want to disallow trailing
+ * content.
+ * Thus, in several implementations below, we pass a 'true' parameter value to
+ * a get_root_value_iterator() method: this indicates that we disallow trailing content.
+ */
+
+simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
+  return get_root_value_iterator().get_root_uint64(true);
 }
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
+simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
+  return get_root_value_iterator().get_root_uint64_in_string(true);
 }
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
+simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
+  return get_root_value_iterator().get_root_int64(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
+simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
+  return get_root_value_iterator().get_root_int64_in_string(true);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
+simdjson_inline simdjson_result<double> document::get_double() noexcept {
+  return get_root_value_iterator().get_root_double(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
+simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
+  return get_root_value_iterator().get_root_double_in_string(true);
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
+simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
+template <typename string_type>
+simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
 }
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
+  return get_root_value_iterator().get_root_wobbly_string(true);
+}
+simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
+  return get_root_value_iterator().get_root_raw_json_string(true);
+}
+simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
+  return get_root_value_iterator().get_root_bool(true);
+}
+simdjson_inline simdjson_result<bool> document::is_null() noexcept {
+  return get_root_value_iterator().is_root_null(true);
 }
 
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
 
+template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
+template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
+template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
+template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
+template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
+template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
+template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
+template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
+template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
 
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
+template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
 
 #if SIMDJSON_EXCEPTIONS
 template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
+simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
+template <class T>
+simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
+simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
+simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
+simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
+simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document::operator value() noexcept(false) { return get_value(); }
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
+#endif
+simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
   auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
+  simdjson_result<size_t> answer = a.count_elements();
+  /* If there was an array, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
   return answer;
 }
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
+simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
   auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
+  simdjson_result<size_t> answer = a.count_fields();
+  /* If there was an object, we are now left pointing at its first element. */
+  if(answer.error() == SUCCESS) { rewind(); }
   return answer;
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
+simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
   auto a = get_array();
   return a.at(index);
 }
+simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
+  return get_array().begin();
+}
+simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
+  return {};
+}
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
   return start_or_resume_object().find_field(key);
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
   return start_or_resume_object().find_field(key);
 }
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
   return start_or_resume_object().find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
   return start_or_resume_object()[key];
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
   return start_or_resume_object()[key];
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+simdjson_inline error_code document::consume() noexcept {
+  bool scalar = false;
+  auto error = is_scalar().get(scalar);
+  if(error) { return error; }
+  if(scalar) {
+    iter.return_current_and_advance();
+    return SUCCESS;
+  }
+  error = iter.skip_child(0);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
+simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
+  auto _iter = get_root_value_iterator();
+  const uint8_t * starting_point{_iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter.unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+}
+
+simdjson_inline simdjson_result<json_type> document::type() noexcept {
+  return get_root_value_iterator().type();
+}
+
+simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
+  // For more speed, we could do:
+  // return iter.is_single_token();
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return ! ((this_type == json_type::array) || (this_type == json_type::object));
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
+simdjson_inline simdjson_result<bool> document::is_string() noexcept {
   json_type this_type;
   auto error = type().get(this_type);
   if(error) { return error; }
   return (this_type == json_type::string);
 }
 
+simdjson_inline bool document::is_negative() noexcept {
+  return get_root_value_iterator().is_root_negative();
+}
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
+  return get_root_value_iterator().is_root_integer(true);
 }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
+  return get_root_value_iterator().get_root_number_type(true);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+
+simdjson_inline simdjson_result<number> document::get_number() noexcept {
+  return get_root_value_iterator().get_root_number(true);
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+
+
+simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
+  auto _iter = get_root_value_iterator();
+  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
 }
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
+simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_pointer.empty()) {
+    return this->get_value();
+  }
+  json_type t;
+  SIMDJSON_TRY(type().get(t));
+  switch (t)
+  {
+    case json_type::array:
+      return (*this).get_array().at_pointer(json_pointer);
+    case json_type::object:
+      return (*this).get_object().at_pointer(json_pointer);
+    default:
+      return INVALID_JSON_POINTER;
+  }
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
+  rewind(); // Rewind the document each time at_pointer is called
+  if (json_path.empty()) {
+      return this->get_value();
+  }
   json_type t;
   SIMDJSON_TRY(type().get(t));
   switch (t) {
@@ -112115,2831 +107102,2591 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
-  lsx::ondemand::value &&value
+simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
+  lsx::ondemand::document &&value
 ) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(
-      std::forward<lsx::ondemand::value>(value)
+    implementation_simdjson_result_base<lsx::ondemand::document>(
+      std::forward<lsx::ondemand::document>(value)
     )
 {
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
+simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
   error_code error
 ) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(error)
+    implementation_simdjson_result_base<lsx::ondemand::document>(
+      error
+    )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_elements() & noexcept {
   if (error()) { return error(); }
   return first.count_elements();
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_fields() & noexcept {
   if (error()) { return error(); }
   return first.count_fields();
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at(size_t index) & noexcept {
   if (error()) { return error(); }
   return first.at(index);
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::rewind() noexcept {
   if (error()) { return error(); }
-  return {};
+  first.rewind();
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::begin() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.begin();
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
   if (error()) { return error(); }
   return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](const char *key) & noexcept {
   if (error()) { return error(); }
   return first[key];
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document>::get_array() & noexcept {
   if (error()) { return error(); }
   return first.get_array();
 }
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document>::get_object() & noexcept {
   if (error()) { return error(); }
   return first.get_object();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64() noexcept {
   if (error()) { return error(); }
   return first.get_uint64();
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64() noexcept {
   if (error()) { return error(); }
   return first.get_int64();
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_int64_in_string();
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double() noexcept {
   if (error()) { return error(); }
   return first.get_double();
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double_in_string() noexcept {
   if (error()) { return error(); }
   return first.get_double_in_string();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_string(bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(allow_replacement);
 }
 template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
   return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_wobbly_string() noexcept {
   if (error()) { return error(); }
   return first.get_wobbly_string();
 }
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document>::get_raw_json_string() noexcept {
   if (error()) { return error(); }
   return first.get_raw_json_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::get_bool() noexcept {
   if (error()) { return error(); }
   return first.get_bool();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::get_value() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.get_value();
 }
-
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_null() noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first.is_null();
 }
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() & noexcept {
   if (error()) { return error(); }
   return first.get<T>();
 }
-template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
+template<typename T>
+simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document>(first).get<T>();
+}
+template<typename T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) & noexcept {
   if (error()) { return error(); }
   return first.get<T>(out);
 }
-
-template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
+template<typename T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) && noexcept {
   if (error()) { return error(); }
-  return std::move(first);
+  return std::forward<lsx::ondemand::document>(first).get<T>(out);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
+template<> simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() & noexcept = delete;
+template<> simdjson_deprecated simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() && noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return std::forward<lsx::ondemand::document>(first);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) & noexcept = delete;
+template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) && noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  out = std::forward<lsx::ondemand::document>(first);
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
+}
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_string() noexcept {
   if (error()) { return error(); }
   return first.is_string();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
+
+simdjson_inline bool simdjson_result<lsx::ondemand::document>::is_negative() noexcept {
   if (error()) { return error(); }
   return first.is_negative();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
+
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_integer() noexcept {
   if (error()) { return error(); }
   return first.is_integer();
 }
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
+
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document>::get_number_type() noexcept {
   if (error()) { return error(); }
   return first.get_number_type();
 }
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document>::get_number() noexcept {
   if (error()) { return error(); }
   return first.get_number();
 }
+
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
+template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::object() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator uint64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator int64_t() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator double() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator bool() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
+}
+simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document>::current_location() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.current_location();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
+simdjson_inline bool simdjson_result<lsx::ondemand::document>::at_end() const noexcept {
   if (error()) { return error(); }
-  return first.raw_json();
+  return first.at_end();
 }
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
+
+simdjson_inline int32_t simdjson_result<lsx::ondemand::document>::current_depth() const noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.current_depth();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_path(std::string_view json_path) noexcept {
+  if (error()) { return error(); }
   return first.at_path(json_path);
 }
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/value-inl.h for lsx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
+simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
+simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
+simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
+simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
+/**
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents.
+ * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
+ * give an error, so we check for trailing content.
+ *
+ * However, for streams of JSON documents, we want to be able to start from
+ * "321" "321" "321"
+ * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
+ * successfully each time.
+ *
+ * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
+ * this indicates that we allow trailing content.
+ */
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
+simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
+simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
+template <typename string_type>
+simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
+simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
+simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
+simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
+simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
+simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
+template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
+template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
+template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
+template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
+template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
+template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
+template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
+template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
+template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
+simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
+simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
+simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
+simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
+simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
+simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
+simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
+simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
+simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
+#endif
+simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
+simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
+simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
+simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
+simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
+simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
+simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
+simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
+simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
+simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
+simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
+simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
+simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
+simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
+simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
+simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
+simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
+simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
+simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
+simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+
+
+namespace simdjson {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::simdjson_result(lsx::ondemand::document_reference value, error_code error)
+  noexcept : implementation_simdjson_result_base<lsx::ondemand::document_reference>(std::forward<lsx::ondemand::document_reference>(value), error) {}
+
+
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_elements() & noexcept {
+  if (error()) { return error(); }
+  return first.count_elements();
 }
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_fields() & noexcept {
+  if (error()) { return error(); }
+  return first.count_fields();
 }
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at(size_t index) & noexcept {
+  if (error()) { return error(); }
+  return first.at(index);
 }
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::rewind() noexcept {
+  if (error()) { return error(); }
+  first.rewind();
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::begin() & noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
+simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::end() & noexcept {
+  return {};
 }
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field_unordered(key);
 }
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
 }
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(const char *key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
+simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document_reference>::get_array() & noexcept {
+  if (error()) { return error(); }
+  return first.get_array();
 }
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
+simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document_reference>::get_object() & noexcept {
+  if (error()) { return error(); }
+  return first.get_object();
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64();
 }
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
+simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_uint64_in_string();
 }
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64();
 }
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
+simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_int64_in_string();
 }
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
-
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double() noexcept {
+  if (error()) { return error(); }
+  return first.get_double();
 }
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
+simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double_in_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_double_in_string();
 }
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(allow_replacement);
 }
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
+template <typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.get_string(receiver, allow_replacement);
 }
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_wobbly_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_wobbly_string();
 }
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document_reference>::get_raw_json_string() noexcept {
+  if (error()) { return error(); }
+  return first.get_raw_json_string();
 }
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::get_bool() noexcept {
+  if (error()) { return error(); }
+  return first.get_bool();
 }
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::get_value() noexcept {
+  if (error()) { return error(); }
+  return first.get_value();
 }
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_null() noexcept {
+  if (error()) { return error(); }
+  return first.is_null();
 }
-#endif
-
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>();
 }
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
+template<typename T>
+simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>();
 }
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) & noexcept {
+  if (error()) { return error(); }
+  return first.get<T>(out);
 }
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+template <class T>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lsx::ondemand::document_reference>(first).get<T>(out);
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document_reference>::type() noexcept {
+  if (error()) { return error(); }
+  return first.type();
 }
-
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_scalar() noexcept {
+  if (error()) { return error(); }
+  return first.is_scalar();
 }
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_string() noexcept {
+  if (error()) { return error(); }
+  return first.is_string();
 }
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) & noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+template <>
+simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) && noexcept {
+  if (error()) { return error(); }
+  out = first;
+  return SUCCESS;
 }
-
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_negative() noexcept {
+  if (error()) { return error(); }
+  return first.is_negative();
 }
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_integer() noexcept {
+  if (error()) { return error(); }
+  return first.is_integer();
 }
-
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document_reference>::get_number_type() noexcept {
+  if (error()) { return error(); }
+  return first.get_number_type();
 }
-
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document_reference>::get_number() noexcept {
+  if (error()) { return error(); }
+  return first.get_number();
 }
-
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+#if SIMDJSON_EXCEPTIONS
+template <class T>
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator T() noexcept(false) {
+  static_assert(std::is_same<T, lsx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
+  static_assert(std::is_same<T, lsx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
+  if (error()) { throw simdjson_error(error()); }
+  return first.get<T>();
 }
-
-
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::array() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::object() & noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator int64_t() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator double() noexcept(false) {
+  if (error()) { throw simdjson_error(error()); }
+  return first;
 }
-
-simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array: {
-      ondemand::array array;
-      SIMDJSON_TRY(get_array().get(array));
-      return array.raw_json();
-    }
-    case json_type::object: {
-      ondemand::object object;
-      SIMDJSON_TRY(get_object().get(object));
-      return object.raw_json();
-    }
-    default:
-      return raw_json_token();
-  }
-}
-
-simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
-  return iter.json_iter().current_location();
-}
-
-simdjson_inline int32_t value::current_depth() const noexcept{
-  return iter.json_iter().depth();
-}
-
-inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
-  if (simdjson_unlikely(json_pointer.empty())) { // can't be
-    return false;
-  }
-  if (simdjson_unlikely(json_pointer[0] != '/')) {
-    return false;
-  }
-  size_t escape = json_pointer.find('~');
-  if (escape == std::string_view::npos) {
-    return true;
-  }
-  if (escape == json_pointer.size() - 1) {
-    return false;
-  }
-  if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
-    return false;
-  }
-  return true;
-}
-
-simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      // a non-empty string can be invalid, or accessing a primitive (issue 2154)
-      if (is_pointer_well_formed(json_pointer)) {
-        return NO_SUCH_FIELD;
-      }
-      return INVALID_JSON_POINTER;
-  }
-}
-
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
-  lsx::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(
-      std::forward<lsx::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>(lsx::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<lsx::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-
-template<> simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::get<lsx::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
-
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator double() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator std::string_view() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::raw_json_string() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator lsx::ondemand::raw_json_string() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator bool() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value>::operator bool() noexcept(false) {
+simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::value() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
   return first;
 }
 #endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::value>::current_location() noexcept {
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document_reference>::current_location() noexcept {
   if (error()) { return error(); }
   return first.current_location();
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<lsx::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return first.raw_json_token();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+  if (error()) { return error(); }
   return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
   if (error()) {
-    return error();
+      return error();
   }
   return first.at_path(json_path);
 }
 
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
-/* end file simdjson/generic/ondemand/value-inl.h for lsx */
-/* including simdjson/generic/ondemand/document-inl.h for lsx: #include "simdjson/generic/ondemand/document-inl.h" */
-/* begin file simdjson/generic/ondemand/document-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
+/* end file simdjson/generic/ondemand/document-inl.h for lsx */
+/* including simdjson/generic/ondemand/document_stream-inl.h for lsx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
+/* begin file simdjson/generic/ondemand/document_stream-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
-  }
+#include <algorithm>
+#include <stdexcept>
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+#ifdef SIMDJSON_THREADS_ENABLED
+
+inline void stage1_worker::finish() {
+  // After calling "run" someone would call finish() to wait
+  // for the end of the processing.
+  // This function will wait until either the thread has done
+  // the processing or, else, the destructor has been called.
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  cond_var.wait(lock, [this]{return has_work == false;});
 }
 
-simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept
-  : iter{std::forward<json_iterator>(_iter)}
-{
-  logger::log_start_value(iter, "document");
+inline stage1_worker::~stage1_worker() {
+  // The thread may never outlive the stage1_worker instance
+  // and will always be stopped/joined before the stage1_worker
+  // instance is gone.
+  stop_thread();
 }
 
-simdjson_inline document document::start(json_iterator &&iter) noexcept {
-  return document(std::forward<json_iterator>(iter));
+inline void stage1_worker::start_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  if(thread.joinable()) {
+    return; // This should never happen but we never want to create more than one thread.
+  }
+  thread = std::thread([this]{
+      while(true) {
+        std::unique_lock<std::mutex> thread_lock(locking_mutex);
+        // We wait for either "run" or "stop_thread" to be called.
+        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
+        // If, for some reason, the stop_thread() method was called (i.e., the
+        // destructor of stage1_worker is called, then we want to immediately destroy
+        // the thread (and not do any more processing).
+        if(!can_work) {
+          break;
+        }
+        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
+              this->_next_batch_start);
+        this->has_work = false;
+        // The condition variable call should be moved after thread_lock.unlock() for performance
+        // reasons but thread sanitizers may report it as a data race if we do.
+        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+        cond_var.notify_one(); // will notify "finish"
+        thread_lock.unlock();
+      }
+    }
+  );
 }
 
-inline void document::rewind() noexcept {
-  iter.rewind();
+
+inline void stage1_worker::stop_thread() {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  // We have to make sure that all locks can be released.
+  can_work = false;
+  has_work = false;
+  cond_var.notify_all();
+  lock.unlock();
+  if(thread.joinable()) {
+    thread.join();
+  }
 }
 
-inline std::string document::to_debug_string() noexcept {
-  return iter.to_string();
+inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
+  std::unique_lock<std::mutex> lock(locking_mutex);
+  owner = ds;
+  _next_batch_start = next_batch_start;
+  stage1_thread_parser = stage1;
+  has_work = true;
+  // The condition variable call should be moved after thread_lock.unlock() for performance
+  // reasons but thread sanitizers may report it as a data race if we do.
+  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
+  cond_var.notify_one(); // will notify the thread lock that we have work
+  lock.unlock();
 }
 
-inline simdjson_result<const char *> document::current_location() const noexcept {
-  return iter.current_location();
+#endif  // SIMDJSON_THREADS_ENABLED
+
+simdjson_inline document_stream::document_stream(
+  ondemand::parser &_parser,
+  const uint8_t *_buf,
+  size_t _len,
+  size_t _batch_size,
+  bool _allow_comma_separated
+) noexcept
+  : parser{&_parser},
+    buf{_buf},
+    len{_len},
+    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
+    allow_comma_separated{_allow_comma_separated},
+    error{SUCCESS}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
+    #endif
+{
+#ifdef SIMDJSON_THREADS_ENABLED
+  if(worker.get() == nullptr) {
+    error = MEMALLOC;
+  }
+#endif
 }
 
-inline int32_t document::current_depth() const noexcept {
-  return iter.depth();
+simdjson_inline document_stream::document_stream() noexcept
+  : parser{nullptr},
+    buf{nullptr},
+    len{0},
+    batch_size{0},
+    allow_comma_separated{false},
+    error{UNINITIALIZED}
+    #ifdef SIMDJSON_THREADS_ENABLED
+    , use_thread(false)
+    #endif
+{
 }
 
-inline bool document::at_end() const noexcept {
-  return iter.at_end();
+simdjson_inline document_stream::~document_stream() noexcept
+{
+  #ifdef SIMDJSON_THREADS_ENABLED
+  worker.reset();
+  #endif
 }
 
+inline size_t document_stream::size_in_bytes() const noexcept {
+  return len;
+}
 
-inline bool document::is_alive() noexcept {
-  return iter.is_alive();
+inline size_t document_stream::truncated_bytes() const noexcept {
+  if(error == CAPACITY) { return len - batch_start; }
+  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
 }
-simdjson_inline value_iterator document::resume_value_iterator() noexcept {
-  return value_iterator(&iter, 1, iter.root_position());
+
+simdjson_inline document_stream::iterator::iterator() noexcept
+  : stream{nullptr}, finished{true} {
 }
-simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
-  return resume_value_iterator();
+
+simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
+  : stream{_stream}, finished{is_end} {
 }
-simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
-  if (iter.at_root()) {
-    return get_object();
-  } else {
-    return object::resume(resume_value_iterator());
-  }
+
+simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
+  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
 }
-simdjson_inline simdjson_result<value> document::get_value() noexcept {
-  // Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
-  // gets called.
 
-  // It is the convention throughout the code that  the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
-  // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  // assert_at_root() serves two purposes: in Debug mode, whether or not
-  // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
-  // the document (this will typically be redundant). In release mode, it generates
-  // SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
-  iter.assert_at_root();
-  switch (*iter.peek()) {
-    case '[': {
-      // The following lines check that the document ends with ].
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_array();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    case '{': {
-      // The following lines would check that the document ends with }.
-      auto value_iterator = get_root_value_iterator();
-      auto error = value_iterator.check_root_object();
-      if(error) { return error; }
-      return value(get_root_value_iterator());
-    }
-    default:
-      // Unfortunately, scalar documents are a special case in simdjson and they cannot
-      // be safely converted to value instances.
-      return SCALAR_DOCUMENT_AS_VALUE;
-  }
-}
-simdjson_inline simdjson_result<array> document::get_array() & noexcept {
-  auto value = get_root_value_iterator();
-  return array::start_root(value);
-}
-simdjson_inline simdjson_result<object> document::get_object() & noexcept {
-  auto value = get_root_value_iterator();
-  return object::start_root(value);
+simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
+  // If there is an error, then we want the iterator
+  // to be finished, no matter what. (E.g., we do not
+  // keep generating documents with errors, or go beyond
+  // a document with errors.)
+  //
+  // Users do not have to call "operator*()" when they use operator++,
+  // so we need to end the stream in the operator++ function.
+  //
+  // Note that setting finished = true is essential otherwise
+  // we would enter an infinite loop.
+  if (stream->error) { finished = true; }
+  // Note that stream->error() is guarded against error conditions
+  // (it will immediately return if stream->error casts to false).
+  // In effect, this next function does nothing when (stream->error)
+  // is true (hence the risk of an infinite loop).
+  stream->next();
+  // If that was the last document, we're finished.
+  // It is the only type of error we do not want to appear
+  // in operator*.
+  if (stream->error == EMPTY) { finished = true; }
+  // If we had any other kind of error (not EMPTY) then we want
+  // to pass it along to the operator* and we cannot mark the result
+  // as "finished" just yet.
+  return *this;
 }
 
-/**
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content. We want to disallow trailing
- * content.
- * Thus, in several implementations below, we pass a 'true' parameter value to
- * a get_root_value_iterator() method: this indicates that we disallow trailing content.
- */
-
-simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
-  return get_root_value_iterator().get_root_uint64(true);
-}
-simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
-  return get_root_value_iterator().get_root_uint64_in_string(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
-  return get_root_value_iterator().get_root_int64(true);
-}
-simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
-  return get_root_value_iterator().get_root_int64_in_string(true);
-}
-simdjson_inline simdjson_result<double> document::get_double() noexcept {
-  return get_root_value_iterator().get_root_double(true);
-}
-simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
-  return get_root_value_iterator().get_root_double_in_string(true);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(true, allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
-  return get_root_value_iterator().get_root_wobbly_string(true);
-}
-simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
-  return get_root_value_iterator().get_root_raw_json_string(true);
-}
-simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
-  return get_root_value_iterator().get_root_bool(true);
-}
-simdjson_inline simdjson_result<bool> document::is_null() noexcept {
-  return get_root_value_iterator().is_root_null(true);
+simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
+  return finished != other.finished;
 }
 
-template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
-
-template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
-template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
+simdjson_inline document_stream::iterator document_stream::begin() noexcept {
+  start();
+  // If there are no documents, we're finished.
+  return iterator(this, error == EMPTY);
+}
 
-template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
-template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
+simdjson_inline document_stream::iterator document_stream::end() noexcept {
+  return iterator(this, true);
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
-template <class T>
-simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
-simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
-simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
-simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
-simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document::operator value() noexcept(false) { return get_value(); }
+inline void document_stream::start() noexcept {
+  if (error) { return; }
+  error = parser->allocate(batch_size);
+  if (error) { return; }
+  // Always run the first stage 1 parse immediately
+  batch_start = 0;
+  error = run_stage1(*parser, batch_start);
+  while(error == EMPTY) {
+    // In exceptional cases, we may start with an empty block
+    batch_start = next_batch_start();
+    if (batch_start >= len) { return; }
+    error = run_stage1(*parser, batch_start);
+  }
+  if (error) { return; }
+  doc_index = batch_start;
+  doc = document(json_iterator(&buf[batch_start], parser));
+  doc.iter._streaming = true;
 
-#endif
-simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
-  auto a = get_array();
-  simdjson_result<size_t> answer = a.count_elements();
-  /* If there was an array, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
-  auto a = get_object();
-  simdjson_result<size_t> answer = a.count_fields();
-  /* If there was an object, we are now left pointing at its first element. */
-  if(answer.error() == SUCCESS) { rewind(); }
-  return answer;
-}
-simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
-simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
-  return {};
+  #ifdef SIMDJSON_THREADS_ENABLED
+  if (use_thread && next_batch_start() < len) {
+    // Kick off the first thread on next batch if needed
+    error = stage1_thread_parser.allocate(batch_size);
+    if (error) { return; }
+    worker->start_thread();
+    start_stage1_thread();
+    if (error) { return; }
+  }
+  #endif // SIMDJSON_THREADS_ENABLED
 }
 
-simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
-  return start_or_resume_object()[key];
-}
+inline void document_stream::next() noexcept {
+  // We always enter at once once in an error condition.
+  if (error) { return; }
+  next_document();
+  if (error) { return; }
+  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
+  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-simdjson_inline error_code document::consume() noexcept {
-  bool scalar = false;
-  auto error = is_scalar().get(scalar);
-  if(error) { return error; }
-  if(scalar) {
-    iter.return_current_and_advance();
-    return SUCCESS;
+  // Check if at end of structural indexes (i.e. at end of batch)
+  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
+    error = EMPTY;
+    // Load another batch (if available)
+    while (error == EMPTY) {
+      batch_start = next_batch_start();
+      if (batch_start >= len) { break; }
+      #ifdef SIMDJSON_THREADS_ENABLED
+      if(use_thread) {
+        load_from_stage1_thread();
+      } else {
+        error = run_stage1(*parser, batch_start);
+      }
+      #else
+      error = run_stage1(*parser, batch_start);
+      #endif
+      /**
+       * Whenever we move to another window, we need to update all pointers to make
+       * it appear as if the input buffer started at the beginning of the window.
+       *
+       * Take this input:
+       *
+       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
+       *
+       * Say you process the following window...
+       *
+       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
+       *
+       * When you do so, the json_iterator has a pointer at the beginning of the memory region
+       * (pointing at the beginning of '{"z"...'.
+       *
+       * When you move to the window that starts at...
+       *
+       * '[7,  10,   9]  [15,  11,   12, 13] ...
+       *
+       * then it is not sufficient to just run stage 1. You also need to re-anchor the
+       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
+       *
+       * Under the DOM front-end, this gets done automatically because the parser owns
+       * the pointer the data, and when you call stage1 and then stage2 on the same
+       * parser, then stage2 will run on the pointer acquired by stage1.
+       *
+       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
+       * we used. But json_iterator has no callback when stage1 is called on the parser.
+       * In fact, I think that the parser is unaware of json_iterator.
+       *
+       *
+       * So we need to re-anchor the json_iterator after each call to stage 1 so that
+       * all of the pointers are in sync.
+       */
+      doc.iter = json_iterator(&buf[batch_start], parser);
+      doc.iter._streaming = true;
+      /**
+       * End of resync.
+       */
+
+      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
+      doc_index = batch_start;
+    }
   }
-  error = iter.skip_child(0);
-  if(error) { iter.abandon(); }
-  return error;
 }
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
-  auto _iter = get_root_value_iterator();
-  const uint8_t * starting_point{_iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter.unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
+inline void document_stream::next_document() noexcept {
+  // Go to next place where depth=0 (document depth)
+  error = doc.iter.skip_child(0);
+  if (error) { return; }
+  // Always set depth=1 at the start of document
+  doc.iter._depth = 1;
+  // consume comma if comma separated is allowed
+  if (allow_comma_separated) { doc.iter.consume_character(','); }
+  // Resets the string buffer at the beginning, thus invalidating the strings.
+  doc.iter._string_buf_loc = parser->string_buf.get();
+  doc.iter._root = doc.iter.position();
 }
 
-simdjson_inline simdjson_result<json_type> document::type() noexcept {
-  return get_root_value_iterator().type();
+inline size_t document_stream::next_batch_start() const noexcept {
+  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
 }
 
-simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
-  // For more speed, we could do:
-  // return iter.is_single_token();
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
+  // This code only updates the structural index in the parser, it does not update any json_iterator
+  // instance.
+  size_t remaining = len - _batch_start;
+  if (remaining <= batch_size) {
+    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
+  } else {
+    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+  }
 }
 
-simdjson_inline simdjson_result<bool> document::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
+  return stream->doc_index;
 }
 
-simdjson_inline bool document::is_negative() noexcept {
-  return get_root_value_iterator().is_root_negative();
-}
+simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
+  auto depth = stream->doc.iter.depth();
+  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
 
-simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
-  return get_root_value_iterator().is_root_integer(true);
-}
+  // If at root, process the first token to determine if scalar value
+  if (stream->doc.iter.at_root()) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':   // Depth=1 already at start of document
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+      default:    // Scalar value document
+        // TODO: We could remove trailing whitespaces
+        // This returns a string spanning from start of value to the beginning of the next document (excluded)
+        {
+          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
+          // normally the length would be next_index - current_index() - 1, except for the last document
+          size_t svlen = next_index - current_index();
+          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
+          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
+            svlen--;
+          }
+          return std::string_view(start, svlen);
+        }
+    }
+    cur_struct_index++;
+  }
 
-simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
-  return get_root_value_iterator().get_root_number_type(true);
+  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
+    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
+      case '{': case '[':
+        depth++;
+        break;
+      case '}': case ']':
+        depth--;
+        break;
+    }
+    if (depth == 0) { break; }
+    cur_struct_index++;
+  }
+
+  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-simdjson_inline simdjson_result<number> document::get_number() noexcept {
-  return get_root_value_iterator().get_root_number(true);
+inline error_code document_stream::iterator::error() const noexcept {
+  return stream->error;
 }
 
+#ifdef SIMDJSON_THREADS_ENABLED
 
-simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
-  auto _iter = get_root_value_iterator();
-  return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_root_length());
-}
+inline void document_stream::load_from_stage1_thread() noexcept {
+  worker->finish();
+  // Swap to the parser that was loaded up in the thread. Make sure the parser has
+  // enough memory to swap to, as well.
+  std::swap(stage1_thread_parser,*parser);
+  error = stage1_thread_error;
+  if (error) { return; }
 
-simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_pointer.empty()) {
-    return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t)
-  {
-    case json_type::array:
-      return (*this).get_array().at_pointer(json_pointer);
-    case json_type::object:
-      return (*this).get_object().at_pointer(json_pointer);
-    default:
-      return INVALID_JSON_POINTER;
+  // If there's anything left, start the stage 1 thread!
+  if (next_batch_start() < len) {
+    start_stage1_thread();
   }
 }
 
-simdjson_inline simdjson_result<value> document::at_path(std::string_view json_path) noexcept {
-  rewind(); // Rewind the document each time at_pointer is called
-  if (json_path.empty()) {
-      return this->get_value();
-  }
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
+inline void document_stream::start_stage1_thread() noexcept {
+  // we call the thread on a lambda that will update
+  // this->stage1_thread_error
+  // there is only one thread that may write to this value
+  // TODO this is NOT exception-safe.
+  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
+  size_t _next_batch_start = this->next_batch_start();
+
+  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
 }
 
+#endif // SIMDJSON_THREADS_ENABLED
+
 } // namespace ondemand
 } // namespace lsx
 } // namespace simdjson
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
-  lsx::ondemand::document &&value
+simdjson_inline simdjson_result<lsx::ondemand::document_stream>::simdjson_result(
+  error_code error
 ) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document>(
-      std::forward<lsx::ondemand::document>(value)
-    )
+    implementation_simdjson_result_base<lsx::ondemand::document_stream>(error)
 {
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::simdjson_result(
-  error_code error
+simdjson_inline simdjson_result<lsx::ondemand::document_stream>::simdjson_result(
+  lsx::ondemand::document_stream &&value
 ) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document>(
-      error
+    implementation_simdjson_result_base<lsx::ondemand::document_stream>(
+      std::forward<lsx::ondemand::document_stream>(value)
     )
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+/* end file simdjson/generic/ondemand/document_stream-inl.h for lsx */
+/* including simdjson/generic/ondemand/field-inl.h for lsx: #include "simdjson/generic/ondemand/field-inl.h" */
+/* begin file simdjson/generic/ondemand/field-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+// clang 6 does not think the default constructor can be noexcept, so we make it explicit
+simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+
+simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
+  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
+{
 }
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
+
+simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
+  raw_json_string key;
+  SIMDJSON_TRY( parent_iter.field_key().get(key) );
+  SIMDJSON_TRY( parent_iter.field_value() );
+  return field::start(parent_iter, key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+
+simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
+    return field(key, parent_iter.child());
 }
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
+  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
+  first.consume();
+  return answer;
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+template <typename string_type>
+simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view key;
+  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
+  receiver = key;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+
+simdjson_inline raw_json_string field::key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return first;
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+
+
+simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline std::string_view field::escaped_key() const noexcept {
+  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
+  auto end_quote = second.iter._json_iter->token.peek(-1);
+  while(*end_quote != '"') end_quote--;
+  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::field>::simdjson_result(
+  lsx::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::field>(
+      std::forward<lsx::ondemand::field>(value)
+    )
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+simdjson_inline simdjson_result<lsx::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lsx::ondemand::field>(error)
+{
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::get_value() noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::field>::key() noexcept {
   if (error()) { return error(); }
-  return first.get_value();
+  return first.key();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_null() noexcept {
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::key_raw_json_token() noexcept {
   if (error()) { return error(); }
-  return first.is_null();
+  return first.key_raw_json_token();
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() & noexcept {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::escaped_key() noexcept {
   if (error()) { return error(); }
-  return first.get<T>();
+  return first.escaped_key();
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document>::get() && noexcept {
+
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first).get<T>();
+  return first.unescaped_key(allow_replacement);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) & noexcept {
+
+template<typename string_type>
+simdjson_inline error_code simdjson_result<lsx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
   if (error()) { return error(); }
-  return first.get<T>(out);
+  return first.unescaped_key(receiver, allow_replacement);
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get(T &out) && noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::field>::value() noexcept {
   if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first).get<T>(out);
+  return std::move(first.value());
 }
 
-template<> simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<lsx::ondemand::document> simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first);
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for lsx */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
 }
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<lsx::ondemand::document>::get<lsx::ondemand::document>(lsx::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<lsx::ondemand::document>(first);
-  return SUCCESS;
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
+  return *this;
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
 
-simdjson_inline bool simdjson_result<lsx::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first).get<T>();
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
 }
 
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
+  }
+  return count == 0;
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
+      }
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
+
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
+    }
+  }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
+SIMDJSON_POP_DISABLE_WARNINGS
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document>(first);
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
 
-simdjson_inline bool simdjson_result<lsx::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-
-simdjson_inline int32_t simdjson_result<lsx::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  out = std::forward<lsx::ondemand::document>(first);
-  return SUCCESS;
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-} // namespace simdjson
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
+}
 
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
+}
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
+}
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-
-
-namespace simdjson {
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::simdjson_result(lsx::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<lsx::ondemand::document_reference>(std::forward<lsx::ondemand::document_reference>(value), error) {}
-
-
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document_reference>(first).get<T>();
-}
-template <class T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-template <class T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document_reference>(first).get<T>(out);
-}
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-template <>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-template <>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, lsx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, lsx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
+#endif
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
+
 #endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
   }
-  return first.at_path(json_path);
+  return true;
 }
 
+} // namespace ondemand
+} // namespace lsx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for lsx */
-/* including simdjson/generic/ondemand/document_stream-inl.h for lsx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::json_iterator>::simdjson_result(lsx::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::json_iterator>(std::forward<lsx::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::json_iterator>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/json_type-inl.h for lsx: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
+}
 
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
+#endif
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
 
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
 
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
+}
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
-{
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
 
-simdjson_inline bool simdjson_result<lsx::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
+simdjson_inline simdjson_result<lsx::ondemand::json_type>::simdjson_result(lsx::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::json_type>(std::forward<lsx::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::json_type>(error) {}
 
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for lsx */
+/* including simdjson/generic/ondemand/logger-inl.h for lsx: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <memory>
+#include <cstring>
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lsx::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
+namespace logger {
+
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
+
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
+  }
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
+{
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline log_level get_log_level_from_env()
+{
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline log_level log_threshold()
+{
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-simdjson_inline simdjson_result<lsx::ondemand::document>::operator lsx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-#endif
-
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_inline bool simdjson_result<lsx::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
+}
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
 
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
+}
 
-simdjson_inline int32_t simdjson_result<lsx::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-} // namespace simdjson
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
+}
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
+  }
+}
 
+} // namespace logger
 } // namespace ondemand
 } // namespace lsx
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for lsx */
+/* including simdjson/generic/ondemand/object-inl.h for lsx: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::simdjson_result(lsx::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<lsx::ondemand::document_reference>(std::forward<lsx::ondemand::document_reference>(value), error) {}
-
+namespace lsx {
+namespace ondemand {
 
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lsx::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lsx::ondemand::array_iterator> simdjson_result<lsx::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lsx::ondemand::array> simdjson_result<lsx::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<lsx::ondemand::object> simdjson_result<lsx::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
 }
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lsx::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<int64_t> simdjson_result<lsx::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
+
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<double> simdjson_result<lsx::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
+
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
+
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lsx::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document_reference>(first).get<T>();
+
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
 }
-template <class T>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::document_reference>(first).get<T>(out);
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
-simdjson_inline simdjson_result<lsx::ondemand::json_type> simdjson_result<lsx::ondemand::document_reference>::type() noexcept {
+
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::object>::simdjson_result(lsx::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::object>(std::forward<lsx::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator> simdjson_result<lsx::ondemand::object>::begin() noexcept {
   if (error()) { return error(); }
-  return first.type();
+  return first.begin();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_scalar() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator> simdjson_result<lsx::ondemand::object>::end() noexcept {
   if (error()) { return error(); }
-  return first.is_scalar();
+  return first.end();
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_string() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.is_string();
+  return first.find_field_unordered(key);
 }
-template <>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) & noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return std::forward<lsx::ondemand::object>(first).find_field_unordered(key);
 }
-template <>
-simdjson_inline error_code simdjson_result<lsx::ondemand::document_reference>::get(lsx::ondemand::document_reference &out) && noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::operator[](std::string_view key) & noexcept {
   if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
+  return first[key];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_negative() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::operator[](std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.is_negative();
+  return std::forward<lsx::ondemand::object>(first)[key];
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lsx::ondemand::document_reference>::is_integer() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.is_integer();
+  return first.find_field(key);
 }
-simdjson_inline simdjson_result<lsx::number_type> simdjson_result<lsx::ondemand::document_reference>::get_number_type() noexcept {
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.get_number_type();
+  return std::forward<lsx::ondemand::object>(first).find_field(key);
 }
-simdjson_inline simdjson_result<lsx::ondemand::number> simdjson_result<lsx::ondemand::document_reference>::get_number() noexcept {
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, lsx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, lsx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+  return first.at_pointer(json_pointer);
 }
-simdjson_inline simdjson_result<lsx::ondemand::document_reference>::operator lsx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::document_reference>::current_location() noexcept {
+inline simdjson_result<bool> simdjson_result<lsx::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return first.current_location();
+  return first.reset();
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::document_reference>::raw_json_token() noexcept {
+inline simdjson_result<bool> simdjson_result<lsx::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.raw_json_token();
+  return first.is_empty();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
+simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  return first.count_fields();
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
 }
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for lsx */
-/* including simdjson/generic/ondemand/document_stream-inl.h for lsx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for lsx */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
-
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
+//
+// object_iterator
+//
 
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
 }
-
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
 }
 
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
-}
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
-{
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
-}
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
+  lsx::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
 {
+  first.iter.assert_is_valid();
 }
-
-simdjson_inline document_stream::~document_stream() noexcept
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
 {
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
 }
-
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
 }
-
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+// Checks for ']' and ','
+simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
+  return *this;
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
-}
+} // namespace simdjson
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
-}
+namespace simdjson {
+namespace lsx {
+namespace ondemand {
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
+
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+#endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
   }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
+}
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
+}
+#endif
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-  #endif // SIMDJSON_THREADS_ENABLED
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+  json.remove_utf8_bom();
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
+}
+
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
   }
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
+}
 
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
+}
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-    }
-    if (depth == 0) { break; }
-    cur_struct_index++;
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
 
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
+}
 
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
   }
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-#endif // SIMDJSON_THREADS_ENABLED
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
+}
 
 } // namespace ondemand
 } // namespace lsx
@@ -114947,612 +109694,468 @@ inline void document_stream::start_stage1_thread() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document_stream>(error)
-{
-}
-simdjson_inline simdjson_result<lsx::ondemand::document_stream>::simdjson_result(
-  lsx::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::document_stream>(
-      std::forward<lsx::ondemand::document_stream>(value)
-    )
-{
-}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
 
-}
+} // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for lsx */
-/* including simdjson/generic/ondemand/field-inl.h for lsx: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for lsx */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for lsx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
+
 namespace lsx {
 namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
-}
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
+  size_t pos{0};
+  while(pos < target.size()) {
+    pos = target.find('"', pos);
+    if(pos == std::string_view::npos) { return true; }
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
+  size_t pos{0};
+  while(target[pos]) {
+    const char * result = strchr(target+pos, '"');
+    if(result == nullptr) { return true; }
+    pos = result - target;
+    if(pos != 0 && target[pos-1] != '\\') { return false; }
+    if(pos > 1 && target[pos-2] == '\\') {
+      size_t backslash_count{2};
+      for(size_t i = 3; i <= pos; i++) {
+        if(target[pos-i] == '\\') { backslash_count++; }
+        else { break; }
+      }
+      if(backslash_count % 2 == 0) { return false; }
+    }
+    pos++;
+  }
+  return true;
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters("), and
+  // the raw content is quote terminated within a valid JSON string.
+  if(target.size() <= SIMDJSON_PADDING) {
+    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+  }
+  const char * r{raw()};
+  size_t pos{0};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::field>::simdjson_result(
-  lsx::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::field>(
-      std::forward<lsx::ondemand::field>(value)
-    )
-{
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
-simdjson_inline simdjson_result<lsx::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lsx::ondemand::field>(error)
-{
+
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
+  return !(a == c);
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::raw_json_string> simdjson_result<lsx::ondemand::field>::key() noexcept {
-  if (error()) { return error(); }
-  return first.key();
+
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
+  return iter.unescape(*this, allow_replacement);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::key_raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.key_raw_json_token();
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
+  return iter.unescape_wobbly(*this);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::escaped_key() noexcept {
-  if (error()) { return error(); }
-  return first.escaped_key();
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
+  bool in_escape = false;
+  const char *s = str.raw();
+  while (true) {
+    switch (*s) {
+      case '\\': in_escape = !in_escape; break;
+      case '"': if (in_escape) { in_escape = false; } else { return out; } break;
+      default: if (in_escape) { in_escape = false; }
+    }
+    out << *s;
+    s++;
+  }
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lsx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+} // namespace ondemand
+} // namespace lsx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(lsx::ondemand::raw_json_string &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(std::forward<lsx::ondemand::raw_json_string>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::raw_json_string>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::raw_json_string>(error) {}
+
+simdjson_inline simdjson_result<const char *> simdjson_result<lsx::ondemand::raw_json_string>::raw() const noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.raw();
 }
-
-template<typename string_type>
-simdjson_inline error_code simdjson_result<lsx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.unescape(iter, allow_replacement);
 }
-
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::field>::value() noexcept {
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<lsx::ondemand::raw_json_string>::unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.unescape_wobbly(iter);
 }
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for lsx */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
+/* end file simdjson/generic/ondemand/raw_json_string-inl.h for lsx */
+/* including simdjson/generic/ondemand/serialization-inl.h for lsx: #include "simdjson/generic/ondemand/serialization-inl.h" */
+/* begin file simdjson/generic/ondemand/serialization-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-namespace lsx {
-namespace ondemand {
-
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
-{
-  other.parser = nullptr;
-}
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
-  return *this;
-}
-
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+inline std::string_view trim(const std::string_view str) noexcept {
+  // We can almost surely do better by rolling our own find_first_not_of function.
+  size_t first = str.find_first_not_of(" \t\n\r");
+  // If we have the empty string (just white space), then no trimming is possible, and
+  // we return the empty string_view.
+  if (std::string_view::npos == first) { return std::string_view(); }
+  size_t last = str.find_last_not_of(" \t\n\r");
+  return str.substr(first, (last - first + 1));
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::document_reference& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::value& x) noexcept {
+  /**
+   * If we somehow receive a value that has already been consumed,
+   * then the following code could be in trouble. E.g., we create
+   * an array as needed, but if an array was already created, then
+   * it could be bad.
+   */
+  using namespace lsx::ondemand;
+  lsx::ondemand::json_type t;
+  auto error = x.type().get(t);
+  if(error != SUCCESS) { return error; }
+  switch (t)
+  {
+    case json_type::array:
     {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
+      lsx::ondemand::array array;
+      error = x.get_array().get(array);
+      if(error) { return error; }
+      return to_json_string(array);
     }
-  }
-  return count == 0;
-}
-
-
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
-  }
-
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
+    case json_type::object:
+    {
+      lsx::ondemand::object object;
+      error = x.get_object().get(object);
+      if(error) { return error; }
+      return to_json_string(object);
     }
+    default:
+      return trim(x.raw_json_token());
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
 }
 
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::object& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+inline simdjson_result<std::string_view> to_json_string(lsx::ondemand::array& x) noexcept {
+  std::string_view v;
+  auto error = x.raw_json().get(v);
+  if(error) {return error; }
+  return trim(v);
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::document_reference> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::value> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::object> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lsx::ondemand::array> x) {
+  if (x.error()) { return x.error(); }
+  return to_json_string(x.value_unsafe());
 }
+} // namespace simdjson
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
-}
+namespace simdjson { namespace lsx { namespace ondemand {
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::value> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
+}
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::value x) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(x).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
-}
-
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-  return reinterpret_cast<const char *>(token.peek());
-}
-
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
-}
-
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
-}
-
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
-
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
-
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
-
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
-
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
-}
-
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
-}
-
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
-}
-
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
 }
-
-simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-  _depth = child_depth;
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::array> x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-simdjson_inline depth_t json_iterator::depth() const noexcept {
-  return _depth;
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::array value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
+#endif
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document_reference& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
+  }
 }
-
-simdjson_inline token_position json_iterator::position() const noexcept {
-  return token.position();
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lsx::ondemand::document_reference>&& x) {
+  if (x.error()) { throw simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
 #else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::document& value)  {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
+  }
 }
-
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
 #endif
-  token.set_position(position);
-  _depth = child_depth;
-}
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    throw simdjson::simdjson_error(error);
   }
-  return TAPE_ERROR;
-}
-
-#if SIMDJSON_DEVELOPMENT_CHECKS
-
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
-}
-
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
-
-#endif
-
-
-simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  return _error;
+inline std::ostream& operator<<(std::ostream& out,  simdjson::simdjson_result<simdjson::lsx::ondemand::object> x) {
+  if (x.error()) { throw  simdjson::simdjson_error(x.error()); }
+  return (out << x.value());
 }
-
-
-simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
-  // This function is not expected to be called in performance-sensitive settings.
-  // Let us guard against silly cases:
-  if((N < max_len) || (N == 0)) { return false; }
-  // Copy to the buffer.
-  std::memcpy(tmpbuf, json, max_len);
-  if(N > max_len) { // We pad whatever remains with ' '.
-    std::memset(tmpbuf + max_len, ' ', N - max_len);
+#else
+inline std::ostream& operator<<(std::ostream& out, simdjson::lsx::ondemand::object value) {
+  std::string_view v;
+  auto error = simdjson::to_json_string(value).get(v);
+  if(error == simdjson::SUCCESS) {
+    return (out << v);
+  } else {
+    return (out << error);
   }
-  return true;
 }
+#endif
+}}} // namespace simdjson::lsx::ondemand
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::json_iterator>::simdjson_result(lsx::ondemand::json_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::json_iterator>(std::forward<lsx::ondemand::json_iterator>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::json_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/json_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/json_type-inl.h for lsx: #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* begin file simdjson/generic/ondemand/json_type-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H
+/* end file simdjson/generic/ondemand/serialization-inl.h for lsx */
+/* including simdjson/generic/ondemand/token_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
@@ -115560,94 +110163,71 @@ namespace simdjson {
 namespace lsx {
 namespace ondemand {
 
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
-    switch (type) {
-        case json_type::array: out << "array"; break;
-        case json_type::object: out << "object"; break;
-        case json_type::number: out << "number"; break;
-        case json_type::string: out << "string"; break;
-        case json_type::boolean: out << "boolean"; break;
-        case json_type::null: out << "null"; break;
-        default: SIMDJSON_UNREACHABLE();
-    }
-    return out;
+simdjson_inline token_iterator::token_iterator(
+  const uint8_t *_buf,
+  token_position position
+) noexcept : buf{_buf}, _position{position}
+{
 }
 
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
-    return out << type.value();
+simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
+  return *(_position);
 }
-#endif
-
 
 
-simdjson_inline number_type number::get_number_type() const noexcept {
-  return type;
+simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
+  return &buf[*(_position++)];
 }
 
-simdjson_inline bool number::is_uint64() const noexcept {
-  return get_number_type() == number_type::unsigned_integer;
+simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
+  return &buf[*position];
 }
-
-simdjson_inline uint64_t number::get_uint64() const noexcept {
-  return payload.unsigned_integer;
+simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
+  return *position;
 }
-
-simdjson_inline number::operator uint64_t() const noexcept {
-  return get_uint64();
+simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
+  return *(position+1) - *position;
 }
 
-simdjson_inline bool number::is_int64() const noexcept {
-  return get_number_type() == number_type::signed_integer;
+simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept {
+  return *(position+2) - *(position) > *(position+1) - *(position) ?
+      *(position+1) - *(position)
+      : *(position+2) - *(position);
 }
-
-simdjson_inline int64_t number::get_int64() const noexcept {
-  return payload.signed_integer;
+simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
+  return &buf[*(_position+delta)];
 }
-
-simdjson_inline number::operator int64_t() const noexcept {
-  return get_int64();
+simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
+  return *(_position+delta);
 }
-
-simdjson_inline bool number::is_double() const noexcept {
-    return get_number_type() == number_type::floating_point_number;
+simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
+  return *(_position+delta+1) - *(_position+delta);
 }
 
-simdjson_inline double number::get_double() const noexcept {
-  return payload.floating_point_number;
+simdjson_inline token_position token_iterator::position() const noexcept {
+  return _position;
 }
-
-simdjson_inline number::operator double() const noexcept {
-  return get_double();
+simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
+  _position = target_position;
 }
 
-simdjson_inline double number::as_double() const noexcept {
-  if(is_double()) {
-    return payload.floating_point_number;
-  }
-  if(is_int64()) {
-    return double(payload.signed_integer);
-  }
-  return double(payload.unsigned_integer);
+simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
+  return _position == other._position;
 }
-
-simdjson_inline void number::append_s64(int64_t value) noexcept {
-  payload.signed_integer = value;
-  type = number_type::signed_integer;
+simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
+  return _position != other._position;
 }
-
-simdjson_inline void number::append_u64(uint64_t value) noexcept {
-  payload.unsigned_integer = value;
-  type = number_type::unsigned_integer;
+simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
+  return _position > other._position;
 }
-
-simdjson_inline void number::append_double(double value) noexcept {
-  payload.floating_point_number = value;
-  type = number_type::floating_point_number;
+simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
+  return _position >= other._position;
 }
-
-simdjson_inline void number::skip_double() noexcept {
-  type = number_type::floating_point_number;
+simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
+  return _position < other._position;
+}
+simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
+  return _position <= other._position;
 }
 
 } // namespace ondemand
@@ -115656,867 +110236,1094 @@ simdjson_inline void number::skip_double() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::json_type>::simdjson_result(lsx::ondemand::json_type &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::json_type>(std::forward<lsx::ondemand::json_type>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::json_type>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::json_type>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(lsx::ondemand::token_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(std::forward<lsx::ondemand::token_iterator>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::token_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::token_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
-/* end file simdjson/generic/ondemand/json_type-inl.h for lsx */
-/* including simdjson/generic/ondemand/logger-inl.h for lsx: #include "simdjson/generic/ondemand/logger-inl.h" */
-/* begin file simdjson/generic/ondemand/logger-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
+/* including simdjson/generic/ondemand/value_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <memory>
-#include <cstring>
-
 namespace simdjson {
 namespace lsx {
 namespace ondemand {
-namespace logger {
-
-static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
-static constexpr const int LOG_EVENT_LEN = 20;
-static constexpr const int LOG_BUFFER_LEN = 30;
-static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
-static int log_depth = 0; // Not threadsafe. Log only.
-
-// Helper to turn unprintable or newline characters into spaces
-static inline char printable_char(char c) {
-  if (c >= 0x20) {
-    return c;
-  } else {
-    return ' ';
-  }
-}
 
-template<typename... Args>
-static inline std::string string_format(const std::string& format, const Args&... args)
+simdjson_inline value_iterator::value_iterator(
+  json_iterator *json_iter,
+  depth_t depth,
+  token_position start_position
+) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
 {
-  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
-  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
-  auto size = static_cast<size_t>(size_s);
-  if (size <= 0) return std::string();
-  std::unique_ptr<char[]> buf(new char[size]);
-  std::snprintf(buf.get(), size, format.c_str(), args...);
-  SIMDJSON_POP_DISABLE_WARNINGS
-  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-static inline log_level get_log_level_from_env()
-{
-  SIMDJSON_PUSH_DISABLE_WARNINGS
-  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
-      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
-  SIMDJSON_POP_DISABLE_WARNINGS
-  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
-  return log_level::info;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_object();
 }
 
-static inline log_level log_threshold()
-{
-  static log_level threshold = get_log_level_from_env();
-  return threshold;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
+  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
+  return started_root_object();
 }
 
-static inline bool should_log(log_level level)
-{
-  return level >= log_threshold();
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
+  assert_at_container_start();
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
+  if (*_json_iter->peek() == '}') {
+    logger::log_value(*_json_iter, "empty object");
+    _json_iter->return_current_and_advance();
+    end_container();
+    return false;
+  }
+  return true;
 }
 
-inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
+    // call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != '}') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
+    }
+    // If the last character is } *and* the first gibberish character is also '}'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed object.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "", type, detail, log_level::info);
-}
-inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
+  auto error = check_root_object();
+  if(error) { return error; }
+  return started_object();
 }
 
-inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
-  log_line(iter, index, depth, "+", type, detail, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
-}
-inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
-  if (LOG_ENABLED) { log_depth++; }
+simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
+#if SIMDJSON_CHECK_EOF
+    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
+    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+    _json_iter->ascend_to(depth()-1);
+    return SUCCESS;
 }
 
-inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  if (LOG_ENABLED) { log_depth--; }
-  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
+  assert_at_next();
 
-inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
-}
-inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
-  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
+  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
+  // obligated to verify there are more tokens if they are not the top level.
+  switch (*_json_iter->return_current_and_advance()) {
+    case '}':
+      logger::log_end_value(*_json_iter, "object");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between object fields");
+  }
 }
 
-inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_event(iter.json_iter(), type, detail, delta, depth_delta);
-}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
+  error_code error;
+  bool has_value;
+  //
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. The start of the object, at the first field:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  if (at_first_field()) {
+    has_value = true;
 
-inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
-  log_value(iter.json_iter(), type, detail, delta, depth_delta);
-}
+  //
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    return false;
 
-inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_start_value(iter.json_iter(), type, delta, depth_delta);
-}
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    if ((error = skip_child() )) { abandon(); return error; }
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
+  while (has_value) {
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
-  log_end_value(iter.json_iter(), type, delta, depth_delta);
-}
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
 
-inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
-  log_error(iter.json_iter(), error, detail, delta, depth_delta);
+  // If the loop ended, we're out of fields to look at.
+  return false;
 }
 
-inline void log_headers() noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(log_level::info))) {
-      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
-      static bool displayed_hint{false};
-      log_depth = 0;
-      printf("\n");
-      if (!displayed_hint) {
-        // We only print this helpful header once.
-        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
-        printf("# +array says 'this is where we were when we discovered the start array'\n");
-        printf(
-            "# -array says 'this is where we were when we ended the array'\n");
-        printf("# skip says 'this is a structural or value I am skipping'\n");
-        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
-        printf("#\n");
-        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
-        printf("# in addition to the depth being displayed.\n");
-        printf("#\n");
-        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
-        printf("# and is not affected by what the token actually is.\n");
-        printf("#\n");
-        printf("# Not all structural elements are presented as tokens in the logs.\n");
-        printf("#\n");
-        printf("# We never give control to the user within an empty array or an empty object.\n");
-        printf("#\n");
-        printf("# Inside an array, having a depth greater than the array's depth means that\n");
-        printf("# we are pointing inside a value.\n");
-        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
-        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
-        displayed_hint = true;
-      }
-      printf("\n");
-      printf("| %-*s ", LOG_EVENT_LEN, "Event");
-      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
-      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
-      // printf("| %-*s ", 5,                    "Next#");
-      printf("| %-*s ", 5, "Depth");
-      printf("| Detail ");
-      printf("|\n");
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
+  /**
+   * When find_field_unordered_raw is called, we can either be pointing at the
+   * first key, pointing outside (at the closing brace) or if a key was matched
+   * we can be either pointing right afterthe ':' right before the value (that we need skip),
+   * or we may have consumed the value and we might be at a comma or at the
+   * final brace (ready for a call to has_next_field()).
+   */
+  error_code error;
+  bool has_value;
 
-      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
-      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
-      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
-      // printf("|%.*s", 5+2, DASHES);
-      printf("|%.*s", 5 + 2, DASHES);
-      printf("|--------");
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
-}
+  // First, we scan from that point to the end.
+  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
+  token_position search_start = _json_iter->position();
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
-  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
-}
+  // We want to know whether we need to go back to the beginning.
+  bool at_first = at_first_field();
+  ///////////////
+  // Initially, the object can be in one of a few different places:
+  //
+  // 1. At the first key:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //      ^ (depth 2, index 1)
+  //    ```
+  //
+  if (at_first) {
+    has_value = true;
 
-template <typename... Args>
-inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
-  if (LOG_ENABLED) {
-    if (simdjson_unlikely(should_log(level))) {
-      const int indent = depth * 2;
-      const auto buf = iter.token.buf;
-      auto msg = string_format(title, std::forward<Args>(args)...);
-      printf("| %*s%s%-*s ", indent, "", title_prefix,
-             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
-      {
-        // Print the current structural.
-        printf("| ");
-        // Before we begin, the index might point right before the document.
-        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
-        if (index < iter._root) {
-          printf("%*s", LOG_BUFFER_LEN, "");
-        } else {
-          auto current_structural = &buf[*index];
-          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
-            printf("%c", printable_char(current_structural[i]));
-          }
-        }
-        printf(" ");
-      }
-      {
-        // Print the next structural.
-        printf("| ");
-        auto next_structural = &buf[*(index + 1)];
-        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
-          printf("%c", printable_char(next_structural[i]));
-        }
-        printf(" ");
-      }
-      // printf("| %5u ", *(index+1));
-      printf("| %5i ", depth);
-      printf("| %6.*s ", int(detail.size()), detail.data());
-      printf("|\n");
-      fflush(stdout);
-    }
-  }
-}
+  // 2. When a previous search did not yield a value or the object is empty:
+  //
+  //    ```
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                     ^ (depth 0)
+  //    { }
+  //        ^ (depth 0, index 2)
+  //    ```
+  //
+  } else if (!is_open()) {
 
-} // namespace logger
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    // If we're past the end of the object, we're being iterated out of order.
+    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
+    // this object iterator will blithely scan that object for fields.
+    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
+#endif
+    SIMDJSON_TRY(reset_object().get(has_value));
+    at_first = true;
+  // 3. When a previous search found a field or an iterator yielded a value:
+  //
+  //    ```
+  //    // When a field was not fully consumed (or not even touched at all)
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //           ^ (depth 2)
+  //    // When a field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                   ^ (depth 1)
+  //    // When the last field was fully consumed
+  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                   ^ (depth 1)
+  //    ```
+  //
+  } else {
+    // If someone queried a key but they not did access the value, then we are left pointing
+    // at the ':' and we need to move forward through the value... If the value was
+    // processed then skip_child() does not move the iterator (but may adjust the depth).
+    if ((error = skip_child() )) { abandon(); return error; }
+    search_start = _json_iter->position();
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+#if SIMDJSON_DEVELOPMENT_CHECKS
+    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  }
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
-/* end file simdjson/generic/ondemand/logger-inl.h for lsx */
-/* including simdjson/generic/ondemand/object-inl.h for lsx: #include "simdjson/generic/ondemand/object-inl.h" */
-/* begin file simdjson/generic/ondemand/object-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+  // After initial processing, we will be in one of two states:
+  //
+  // ```
+  // // At the beginning of a field
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //   ^ (depth 1)
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                  ^ (depth 1)
+  // // At the end of the object
+  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
+  //                                  ^ (depth 0)
+  // ```
+  //
+  // Next, we find a match starting from the current position.
+  while (has_value) {
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value. It will also increment the depth by one.
+    if ((error = field_value() )) { abandon(); return error; }
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
+    }
 
-simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
+  }
+  // Performance note: it maybe wasteful to rewind to the beginning when there might be
+  // no other query following. Indeed, it would require reskipping the whole object.
+  // Instead, you can just stay where you are. If there is a new query, there is always time
+  // to rewind.
+  if(at_first) { return false; }
 
-simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
+  // If we reach the end without finding a match, search the rest of the fields starting at the
+  // beginning of the object.
+  // (We have already run through the object before, so we've already validated its structure. We
+  // don't check errors in this bit.)
+  SIMDJSON_TRY(reset_object().get(has_value));
+  while (true) {
+    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
+    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
 
+    // Get the key and colon, stopping at the value.
+    raw_json_string actual_key;
+    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
+    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
+    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
+    // The depth is left unchanged by field_key().
+    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
+    // field_value() will advance and check that we find a ':' separating the
+    // key and the value.  It will also increment the depth by one.
+    error = field_value(); SIMDJSON_ASSUME(!error);
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
-  size_t pos{0};
-  while(pos < target.size()) {
-    pos = target.find('"', pos);
-    if(pos == std::string_view::npos) { return true; }
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
+    // If it matches, stop and return
+    // We could do it this way if we wanted to allow arbitrary
+    // key content (including escaped quotes).
+    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
+    // Instead we do the following which may trigger buffer overruns if the
+    // user provides an adversarial key (containing a well placed unescaped quote
+    // character and being longer than the number of bytes remaining in the JSON
+    // input).
+    if (actual_key.unsafe_is_equal(key)) {
+      logger::log_event(*this, "match", key, -2);
+      // If we return here, then we return while pointing at the ':' that we just checked.
+      return true;
     }
-    pos++;
-  }
-  return value(iter.child());
-}
-simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
+
+    // No match: skip the value and see if , or } is next
+    logger::log_event(*this, "no match", key, -2);
+    // The call to skip_child is meant to skip over the value corresponding to the key.
+    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
+    SIMDJSON_TRY( skip_child() );
+    // If we reached the end of the key-value pair we started from, then we know
+    // that the key is not there so we return false. We are either right before
+    // the next comma or the final brace.
+    if(_json_iter->position() == search_start) { return false; }
+    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
+    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
+    // then we are in error and we abort.
+    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
+    // If we make the mistake of exiting here, then we could be left pointing at a key
+    // in the middle of an object. That's not an allowable state.
   }
-  return value(iter.child());
+  // If the loop ended, we're out of fields to look at. The program should
+  // never reach this point.
+  return false;
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
-  return find_field_unordered(key);
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
+  assert_at_next();
+
+  const uint8_t *key = _json_iter->return_current_and_advance();
+  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
+  return raw_json_string(key);
 }
-simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
-  return std::forward<object>(*this).find_field_unordered(key);
+
+simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
+  assert_at_next();
+
+  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
+  _json_iter->descend_to(depth()+1);
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_array();
 }
-simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
-  bool has_value;
-  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
-  if (!has_value) {
-    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
-    return NO_SUCH_FIELD;
-  }
-  return value(iter.child());
+
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
+  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
+  return started_root_array();
 }
 
-simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
-  size_t pos{0};
-  while(target[pos]) {
-    const char * result = strchr(target+pos, '"');
-    if(result == nullptr) { return true; }
-    pos = result - target;
-    if(pos != 0 && target[pos-1] != '\\') { return false; }
-    if(pos > 1 && target[pos-2] == '\\') {
-      size_t backslash_count{2};
-      for(size_t i = 3; i <= pos; i++) {
-        if(target[pos-i] == '\\') { backslash_count++; }
-        else { break; }
-      }
-      if(backslash_count % 2 == 0) { return false; }
-    }
-    pos++;
-  }
-  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
-  if(error_skip) { iter.abandon(); }
-  return error_skip;
+inline std::string value_iterator::to_string() const noexcept {
+  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
+  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
+  answer += std::string(" ]");
+  return answer;
 }
 
-simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  const uint8_t * final_point{iter._json_iter->peek()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
-
-simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
-  SIMDJSON_TRY( iter.started_object().error() );
-  return object(iter);
-}
-
-simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
-  // Assumptions: does not contain unescaped quote characters("), and
-  // the raw content is quote terminated within a valid JSON string.
-  if(target.size() <= SIMDJSON_PADDING) {
-    return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
-  }
-  const char * r{raw()};
-  size_t pos{0};
-  for(;pos < target.size();pos++) {
-    if(r[pos] != target[pos]) { return false; }
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
+  assert_at_container_start();
+  if (*_json_iter->peek() == ']') {
+    logger::log_value(*_json_iter, "empty array");
+    _json_iter->return_current_and_advance();
+    SIMDJSON_TRY( end_container() );
+    return false;
   }
-  if(r[pos] != '"') { return false; }
+  _json_iter->descend_to(depth()+1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  _json_iter->set_start_position(_depth, start_position());
+#endif
   return true;
 }
 
-simdjson_inline object::object(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
+simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
+  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
+  // current document. It only works in the normal mode where we have indexed a single document.
+  // Note that adding a check for 'streaming' is not expensive since we only have at most
+  // one root element.
+  if ( ! _json_iter->streaming() ) {
+    // The following lines do not fully protect against garbage content within the
+    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
+    // also call `at_end()` on the document instance at the end of the processing to
+    // ensure that the processing has finished at the end.
+    //
+    if (*_json_iter->peek_last() != ']') {
+      _json_iter->abandon();
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
+    }
+    // If the last character is ] *and* the first gibberish character is also ']'
+    // then on-demand could accidentally go over. So we need additional checks.
+    // https://github.com/simdjson/simdjson/issues/1834
+    // Checking that the document is balanced requires a full scan which is potentially
+    // expensive, but it only happens in edge cases where the first padding character is
+    // a closing bracket.
+    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
+      _json_iter->abandon();
+      // The exact error would require more work. It will typically be an unclosed array.
+      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
+    }
+  }
+  return SUCCESS;
 }
 
-simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return object_iterator(iter);
-}
-simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
-  return object_iterator(iter);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
+  auto error = check_root_array();
+  if (error) { return error; }
+  return started_array();
 }
 
-inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  size_t slash = json_pointer.find('/');
-  std::string_view key = json_pointer.substr(0, slash);
-  // Grab the child with the given key
-  simdjson_result<value> child;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
+  assert_at_next();
 
-  // If there is an escape character in the key, unescape it and then get the child.
-  size_t escape = key.find('~');
-  if (escape != std::string_view::npos) {
-    // Unescape the key
-    std::string unescaped(key);
-    do {
-      switch (unescaped[escape+1]) {
-        case '0':
-          unescaped.replace(escape, 2, "~");
-          break;
-        case '1':
-          unescaped.replace(escape, 2, "/");
-          break;
-        default:
-          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
-      }
-      escape = unescaped.find('~', escape+1);
-    } while (escape != std::string::npos);
-    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
-  } else {
-    child = find_field(key);
-  }
-  if(child.error()) {
-    return child; // we do not continue if there was an error
-  }
-  // If there is a /, we have to recurse and look up more of the path
-  if (slash != std::string_view::npos) {
-    child = child.at_pointer(json_pointer.substr(slash));
+  logger::log_event(*this, "has_next_element");
+  switch (*_json_iter->return_current_and_advance()) {
+    case ']':
+      logger::log_end_value(*_json_iter, "array");
+      SIMDJSON_TRY( end_container() );
+      return false;
+    case ',':
+      _json_iter->descend_to(depth()+1);
+      return true;
+    default:
+      return report_error(TAPE_ERROR, "Missing comma between array elements");
   }
-  return child;
 }
 
-inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") {
-    return INVALID_JSON_POINTER;
-  }
-  return at_pointer(json_pointer);
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
+  auto not_true = atomparsing::str4ncmp(json, "true");
+  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
+  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
+  if (error) { return incorrect_type_error("Not a boolean"); }
+  return simdjson_result<bool>(!not_true);
 }
-
-simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the object after counting the number of elements.
-  iter.reset_object();
-  return count;
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
+  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
+  // if we start with 'n', we must be a null
+  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
+  return is_null_string;
 }
 
-simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_object().get(is_not_empty);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
+  return get_raw_json_string().unescape(json_iter(), allow_replacement);
+}
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_string(allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
+  return get_raw_json_string().unescape_wobbly(json_iter());
+}
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  advance_scalar("string");
+  return raw_json_string(json+1);
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
+  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
+  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
+  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
+  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
+  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
+  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
+  auto result = parse_bool(peek_non_root_scalar("bool"));
+  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
+  bool is_null_value;
+  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
+  if(is_null_value) { advance_non_root_scalar("null"); }
+  return is_null_value;
+}
+simdjson_inline bool value_iterator::is_negative() noexcept {
+  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
+}
+simdjson_inline bool value_iterator::is_root_negative() noexcept {
+  return numberparsing::is_negative(peek_root_scalar("numbersign"));
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
+  return numberparsing::is_integer(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
+  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
+}
+simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
+  number num;
+  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
   if(error) { return error; }
-  return !is_not_empty;
+  return num;
 }
 
-simdjson_inline simdjson_result<bool> object::reset() & noexcept {
-  return iter.reset_object();
+simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("is_root_integer");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    return false; // if there are more than 20 characters, it cannot be represented as an integer.
+  }
+  auto answer = numberparsing::is_integer(tmpbuf);
+  // If the parsing was a success, we must still check that it is
+  // a single scalar. Note that we parse first because of cases like '[]' where
+  // getting TRAILING_CONTENT is wrong.
+  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
+  return answer;
 }
 
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::object>::simdjson_result(lsx::ondemand::object &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::object>(std::forward<lsx::ondemand::object>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::object>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::object>(error) {}
-
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator> simdjson_result<lsx::ondemand::object>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
+simdjson_inline simdjson_result<lsx::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return number_type::big_integer;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  auto answer = numberparsing::get_number_type(tmpbuf);
+  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  return answer;
 }
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator> simdjson_result<lsx::ondemand::object>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
+simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("number");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
+  uint8_t tmpbuf[1074+8+1+1];
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    if(numberparsing::check_if_integer(json, max_len)) {
+      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
+      return BIGINT_ERROR;
+    }
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
+    return NUMBER_ERROR;
+  }
+  number num;
+  error_code error =  numberparsing::parse_number(tmpbuf, num);
+  if(error) { return error; }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_root_scalar("number");
+  return num;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::object>(first).find_field_unordered(key);
+template <typename string_type>
+simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
+  std::string_view content;
+  auto err = get_root_string(check_trailing, allow_replacement).get(content);
+  if (err) { return err; }
+  receiver = content;
+  return SUCCESS;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
+simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
+  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::operator[](std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::object>(first)[key];
+simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
+  auto json = peek_scalar("string");
+  if (*json != '"') { return incorrect_type_error("Not a string"); }
+  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+  advance_scalar("string");
+  return raw_json_string(json+1);
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::find_field(std::string_view key) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lsx::ondemand::object>(first).find_field(key);
+simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("uint64");
+  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("uint64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+  auto result = numberparsing::parse_integer(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
+  }
+  return result;
 }
+simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("int64");
+  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
+  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
+    return NUMBER_ERROR;
+  }
 
-simdjson_inline simdjson_result<lsx::ondemand::value> simdjson_result<lsx::ondemand::object>::at_path(
-    std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
+  auto result = numberparsing::parse_integer_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("int64");
   }
-  return first.at_path(json_path);
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
 }
 
-inline simdjson_result<bool> simdjson_result<lsx::ondemand::object>::reset() noexcept {
-  if (error()) { return error(); }
-  return first.reset();
+simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("double");
+  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
+  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
+  // number: -0.<fraction>e-308.
+  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
+  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
+    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
+    return NUMBER_ERROR;
+  }
+  auto result = numberparsing::parse_double_in_string(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("double");
+  }
+  return result;
+}
+simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("bool");
+  uint8_t tmpbuf[5+1+1]; // +1 for null termination
+  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
+  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
+  auto result = parse_bool(tmpbuf);
+  if(result.error() == SUCCESS) {
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("bool");
+  }
+  return result;
+}
+simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
+  auto max_len = peek_root_length();
+  auto json = peek_root_scalar("null");
+  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
+  if(result) { // we have something that looks like a null.
+    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
+    advance_root_scalar("null");
+  } else if (json[0] == 'n') {
+    return incorrect_type_error("Not a null but starts with n");
+  }
+  return result;
 }
 
-inline simdjson_result<bool> simdjson_result<lsx::ondemand::object>::is_empty() noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
+simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
+
+  return _json_iter->skip_child(depth());
 }
 
-simdjson_inline  simdjson_result<size_t> simdjson_result<lsx::ondemand::object>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
+simdjson_inline value_iterator value_iterator::child() const noexcept {
+  assert_at_child();
+  return { _json_iter, depth()+1, _json_iter->token.position() };
 }
 
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lsx::ondemand::object>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
+// marked non-inline.
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline bool value_iterator::is_open() const noexcept {
+  return _json_iter->depth() >= depth();
 }
-} // namespace simdjson
+SIMDJSON_POP_DISABLE_WARNINGS
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
-/* end file simdjson/generic/ondemand/object-inl.h for lsx */
-/* including simdjson/generic/ondemand/object_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+simdjson_inline bool value_iterator::at_end() const noexcept {
+  return _json_iter->at_end();
+}
 
-//
-// object_iterator
-//
+simdjson_inline bool value_iterator::at_start() const noexcept {
+  return _json_iter->token.position() == start_position();
+}
 
-simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+simdjson_inline bool value_iterator::at_first_field() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  return _json_iter->token.position() == start_position() + 1;
+}
 
-simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
-  error_code error = iter.error();
-  if (error) { iter.abandon(); return error; }
-  auto result = field::start(iter);
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (result.error()) { iter.abandon(); }
-  return result;
+simdjson_inline void value_iterator::abandon() noexcept {
+  _json_iter->abandon();
 }
-simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
-  return !(*this != other);
+
+simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
-  return iter.is_open();
+simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
+  return _json_iter->error;
 }
-
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline object_iterator &object_iterator::operator++() noexcept {
-  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
-  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
-  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
-
-  simdjson_unused error_code error;
-  if ((error = iter.skip_child() )) { return *this; }
-
-  simdjson_unused bool has_value;
-  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
-  return *this;
+simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
+  return _json_iter->string_buf_loc();
 }
-SIMDJSON_POP_DISABLE_WARNINGS
-
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the object is first found and the iterator is just past the {.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the , or } before the next value. In this state,
-//   depth == iter.depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter.depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the object iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
-//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
-//
-// Errors that occur while reading a field to give to the user (such as when the key is not a
-// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
-// moving to the Finished state without transitioning through an Error state at all.
-//
-// ## Terminal State
-//
-// The terminal state has iter.depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
-//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
-//
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(
-  lsx::ondemand::object_iterator &&value
-) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>(std::forward<lsx::ondemand::object_iterator>(value))
-{
-  first.iter.assert_is_valid();
+simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
+  return *_json_iter;
 }
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
-  : implementation_simdjson_result_base<lsx::ondemand::object_iterator>({}, error)
-{
+simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
+  return *_json_iter;
 }
 
-simdjson_inline simdjson_result<lsx::ondemand::field> simdjson_result<lsx::ondemand::object_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator==(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
+simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
+  return _json_iter->peek(start_position());
 }
-// If we're iterating and there is an error, return the error once.
-simdjson_inline bool simdjson_result<lsx::ondemand::object_iterator>::operator!=(const simdjson_result<lsx::ondemand::object_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
+simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
+  return _json_iter->peek_length(start_position());
 }
-// Checks for ']' and ','
-simdjson_inline simdjson_result<lsx::ondemand::object_iterator> &simdjson_result<lsx::ondemand::object_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++first;
-  return *this;
+simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
+  return _json_iter->peek_root_length(start_position());
 }
 
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/object_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/parser-inl.h for lsx: #include "simdjson/generic/ondemand/parser-inl.h" */
-/* begin file simdjson/generic/ondemand/parser-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return peek_start(); }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  return _json_iter->peek();
+}
 
-namespace simdjson {
-namespace lsx {
-namespace ondemand {
+simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  if (!is_at_start()) { return; }
 
-simdjson_inline parser::parser(size_t max_capacity) noexcept
-  : _max_capacity{max_capacity} {
+  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
+  assert_at_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
 }
 
-simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
-  if (new_capacity > max_capacity()) { return CAPACITY; }
-  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
-
-  // string_capacity copied from document::allocate
-  _capacity = 0;
-  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
-  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
+  logger::log_start_value(*_json_iter, start_position(), depth(), type);
+  // If we're not at the position anymore, we don't want to advance the cursor.
+  const uint8_t *json;
+  if (!is_at_start()) {
 #if SIMDJSON_DEVELOPMENT_CHECKS
-  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
+    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
 #endif
-  if (implementation) {
-    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
-    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+    json = peek_start();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
   } else {
-    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+    assert_at_start();
+    /**
+     * We should be prudent. Let us peek. If it is not the right type, we
+     * return an error. Only once we have determined that we have the right
+     * type are we allowed to advance!
+     */
+    json = _json_iter->peek();
+    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
+    _json_iter->return_current_and_advance();
   }
-  _capacity = new_capacity;
-  _max_depth = new_max_depth;
+
+
   return SUCCESS;
 }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
-  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
-}
-#endif
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-  json.remove_utf8_bom();
+simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_root();
+  return _json_iter->peek();
+}
+simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return peek_start(); }
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
+  assert_at_non_root_start();
+  return _json_iter->peek();
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  json.remove_utf8_bom();
+  assert_at_root();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
+simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
+  logger::log_value(*_json_iter, start_position(), depth(), type);
+  if (!is_at_start()) { return; }
 
-  // Allocate if needed
-  if (capacity() < json.length() || !string_buf) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+  assert_at_non_root_start();
+  _json_iter->return_current_and_advance();
+  _json_iter->ascend_to(depth()-1);
+}
 
-  // Run stage 1.
-  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
-  if (err) {
-    if (err != UNCLOSED_STRING)
-      return err;
-  }
-  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
+simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
+  logger::log_error(*_json_iter, start_position(), depth(), message);
+  return INCORRECT_TYPE;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_start() const noexcept {
+  return position() == start_position();
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, len, allocated));
+simdjson_inline bool value_iterator::is_at_key() const noexcept {
+  // Keys are at the same depth as the object.
+  // Note here that we could be safer and check that we are within an object,
+  // but we do not.
+  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
-  return iterate(padded_string_view(json, allocated));
+simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
+  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
+  auto delta = position() - start_position();
+  return delta == 1 || delta == 2;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
-  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
-    json.reserve(json.size() + SIMDJSON_PADDING);
-  }
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
-  return iterate(padded_string_view(json));
+inline void value_iterator::assert_at_container_start() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  padded_string_view json = result.value_unsafe();
-  return iterate(json);
+inline void value_iterator::assert_at_next() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
-  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
-  SIMDJSON_TRY( result.error() );
-  const padded_string &json = result.value_unsafe();
-  return iterate(json);
+simdjson_inline void value_iterator::move_at_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position);
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
-  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+simdjson_inline void value_iterator::move_at_container_start() noexcept {
+  _json_iter->_depth = _depth;
+  _json_iter->token.set_position(_start_position + 1);
+}
 
-  json.remove_utf8_bom();
+simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_array();
+}
 
-  // Allocate if needed
-  if (capacity() < json.length()) {
-    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
-  }
+simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
+  if(error()) { return error(); }
+  move_at_container_start();
+  return started_object();
+}
 
-  // Run stage 1.
-  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
-  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
+inline void value_iterator::assert_at_child() const noexcept {
+  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
+  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
+  SIMDJSON_ASSUME( _depth > 0 );
 }
 
-inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
-  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
-    buf += 3;
-    len -= 3;
-  }
-  if(allow_comma_separated && batch_size < len) { batch_size = len; }
-  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
+inline void value_iterator::assert_at_root() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_at_non_root_start() const noexcept {
+  assert_at_start();
+  SIMDJSON_ASSUME( _depth > 1 );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+inline void value_iterator::assert_is_valid() const noexcept {
+  SIMDJSON_ASSUME( _json_iter != nullptr );
 }
-inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
-  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+
+simdjson_inline bool value_iterator::is_valid() const noexcept {
+  return _json_iter != nullptr;
 }
 
-simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
-  return _capacity;
+simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
+  switch (*peek_start()) {
+    case '{':
+      return json_type::object;
+    case '[':
+      return json_type::array;
+    case '"':
+      return json_type::string;
+    case 'n':
+      return json_type::null;
+    case 't': case 'f':
+      return json_type::boolean;
+    case '-':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return json_type::number;
+    default:
+      return TAPE_ERROR;
+  }
 }
-simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
-  return _max_capacity;
+
+simdjson_inline token_position value_iterator::start_position() const noexcept {
+  return _start_position;
 }
-simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
-  return _max_depth;
+
+simdjson_inline token_position value_iterator::position() const noexcept {
+  return _json_iter->position();
 }
 
-simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
-  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
-    _max_capacity = max_capacity;
-  } else {
-    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
-  }
+simdjson_inline token_position value_iterator::end_position() const noexcept {
+  return _json_iter->end_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
-  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline token_position value_iterator::last_position() const noexcept {
+  return _json_iter->last_position();
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
-  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
-  if (!end) { return STRING_ERROR; }
-  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
-  dst = end;
-  return result;
+simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
+  return _json_iter->report_error(error, message);
 }
 
 } // namespace ondemand
@@ -116525,3331 +111332,847 @@ simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::u
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(lsx::ondemand::parser &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(std::forward<lsx::ondemand::parser>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::parser>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::parser>(error) {}
+simdjson_inline simdjson_result<lsx::ondemand::value_iterator>::simdjson_result(lsx::ondemand::value_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::value_iterator>(std::forward<lsx::ondemand::value_iterator>(value)) {}
+simdjson_inline simdjson_result<lsx::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lsx::ondemand::value_iterator>(error) {}
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/token_iterator-inl.h for lsx */
-/* including simdjson/generic/ondemand/value_iterator-inl.h for lsx: #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
 
+
+/* end file simdjson/generic/ondemand/amalgamated.h for lsx */
+/* including simdjson/lsx/end.h: #include "simdjson/lsx/end.h" */
+/* begin file simdjson/lsx/end.h */
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-namespace simdjson {
-
-namespace lsx {
-namespace ondemand {
+#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
+/* undefining SIMDJSON_IMPLEMENTATION from "lsx" */
+#undef SIMDJSON_IMPLEMENTATION
+/* end file simdjson/lsx/end.h */
 
-simdjson_inline value_iterator::value_iterator(
-  json_iterator *json_iter,
-  depth_t depth,
-  token_position start_position
-) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
-{
-}
+#endif // SIMDJSON_LSX_ONDEMAND_H
+/* end file simdjson/lsx/ondemand.h */
+#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
+/* including simdjson/lasx/ondemand.h: #include "simdjson/lasx/ondemand.h" */
+/* begin file simdjson/lasx/ondemand.h */
+#ifndef SIMDJSON_LASX_ONDEMAND_H
+#define SIMDJSON_LASX_ONDEMAND_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_object();
-}
+/* including simdjson/lasx/begin.h: #include "simdjson/lasx/begin.h" */
+/* begin file simdjson/lasx/begin.h */
+/* defining SIMDJSON_IMPLEMENTATION to "lasx" */
+#define SIMDJSON_IMPLEMENTATION lasx
+/* including simdjson/lasx/base.h: #include "simdjson/lasx/base.h" */
+/* begin file simdjson/lasx/base.h */
+#ifndef SIMDJSON_LASX_BASE_H
+#define SIMDJSON_LASX_BASE_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_object() noexcept {
-  SIMDJSON_TRY( start_container('{', "Not an object", "object") );
-  return started_root_object();
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
-  assert_at_container_start();
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
-#endif
-  if (*_json_iter->peek() == '}') {
-    logger::log_value(*_json_iter, "empty object");
-    _json_iter->return_current_and_advance();
-    end_container();
-    return false;
-  }
-  return true;
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
-    // call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != '}') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
-    }
-    // If the last character is } *and* the first gibberish character is also '}'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed object.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_object() noexcept {
-  auto error = check_root_object();
-  if(error) { return error; }
-  return started_object();
-}
-
-simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
-#if SIMDJSON_CHECK_EOF
-    if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
-    // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-    _json_iter->ascend_to(depth()-1);
-    return SUCCESS;
-}
+namespace simdjson {
+/**
+ * Implementation for LASX.
+ */
+namespace lasx {
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
-  assert_at_next();
+class implementation;
 
-  // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
-  // obligated to verify there are more tokens if they are not the top level.
-  switch (*_json_iter->return_current_and_advance()) {
-    case '}':
-      logger::log_end_value(*_json_iter, "object");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between object fields");
-  }
-}
+namespace {
+namespace simd {
+template <typename T> struct simd8;
+template <typename T> struct simd8x64;
+} // namespace simd
+} // unnamed namespace
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
-  error_code error;
-  bool has_value;
-  //
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. The start of the object, at the first field:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  if (at_first_field()) {
-    has_value = true;
+} // namespace lasx
+} // namespace simdjson
 
-  //
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    return false;
+#endif // SIMDJSON_LASX_BASE_H
+/* end file simdjson/lasx/base.h */
+/* including simdjson/lasx/intrinsics.h: #include "simdjson/lasx/intrinsics.h" */
+/* begin file simdjson/lasx/intrinsics.h */
+#ifndef SIMDJSON_LASX_INTRINSICS_H
+#define SIMDJSON_LASX_INTRINSICS_H
 
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    if ((error = skip_child() )) { abandon(); return error; }
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
-  while (has_value) {
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    //if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() ); // Skip the value entirely
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
+// This should be the correct header whether
+// you use visual studio or other compilers.
+#include <lasxintrin.h>
 
-  // If the loop ended, we're out of fields to look at.
-  return false;
-}
+static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch ASX");
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
-  /**
-   * When find_field_unordered_raw is called, we can either be pointing at the
-   * first key, pointing outside (at the closing brace) or if a key was matched
-   * we can be either pointing right afterthe ':' right before the value (that we need skip),
-   * or we may have consumed the value and we might be at a comma or at the
-   * final brace (ready for a call to has_next_field()).
-   */
-  error_code error;
-  bool has_value;
+#endif //  SIMDJSON_LASX_INTRINSICS_H
+/* end file simdjson/lasx/intrinsics.h */
+/* including simdjson/lasx/bitmanipulation.h: #include "simdjson/lasx/bitmanipulation.h" */
+/* begin file simdjson/lasx/bitmanipulation.h */
+#ifndef SIMDJSON_LASX_BITMANIPULATION_H
+#define SIMDJSON_LASX_BITMANIPULATION_H
 
-  // First, we scan from that point to the end.
-  // If we don't find a match, we may loop back around, and scan from the beginning to that point.
-  token_position search_start = _json_iter->position();
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmask.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  // We want to know whether we need to go back to the beginning.
-  bool at_first = at_first_field();
-  ///////////////
-  // Initially, the object can be in one of a few different places:
-  //
-  // 1. At the first key:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //      ^ (depth 2, index 1)
-  //    ```
-  //
-  if (at_first) {
-    has_value = true;
+namespace simdjson {
+namespace lasx {
+namespace {
 
-  // 2. When a previous search did not yield a value or the object is empty:
-  //
-  //    ```
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                     ^ (depth 0)
-  //    { }
-  //        ^ (depth 0, index 2)
-  //    ```
-  //
-  } else if (!is_open()) {
+// We sometimes call trailing_zero on inputs that are zero,
+// but the algorithms do not end up using the returned value.
+// Sadly, sanitizers are not smart enough to figure it out.
+SIMDJSON_NO_SANITIZE_UNDEFINED
+// This function can be used safely even if not all bytes have been
+// initialized.
+// See issue https://github.com/simdjson/simdjson/issues/1965
+SIMDJSON_NO_SANITIZE_MEMORY
+simdjson_inline int trailing_zeroes(uint64_t input_num) {
+  return __builtin_ctzll(input_num);
+}
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    // If we're past the end of the object, we're being iterated out of order.
-    // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
-    // this object iterator will blithely scan that object for fields.
-    if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    SIMDJSON_TRY(reset_object().get(has_value));
-    at_first = true;
-  // 3. When a previous search found a field or an iterator yielded a value:
-  //
-  //    ```
-  //    // When a field was not fully consumed (or not even touched at all)
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //           ^ (depth 2)
-  //    // When a field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                   ^ (depth 1)
-  //    // When the last field was fully consumed
-  //    { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                   ^ (depth 1)
-  //    ```
-  //
-  } else {
-    // If someone queried a key but they not did access the value, then we are left pointing
-    // at the ':' and we need to move forward through the value... If the value was
-    // processed then skip_child() does not move the iterator (but may adjust the depth).
-    if ((error = skip_child() )) { abandon(); return error; }
-    search_start = _json_iter->position();
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  }
+/* result might be undefined when input_num is zero */
+simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
+  return input_num & (input_num-1);
+}
 
-  // After initial processing, we will be in one of two states:
-  //
-  // ```
-  // // At the beginning of a field
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //   ^ (depth 1)
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                  ^ (depth 1)
-  // // At the end of the object
-  // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
-  //                                  ^ (depth 0)
-  // ```
-  //
-  // Next, we find a match starting from the current position.
-  while (has_value) {
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+/* result might be undefined when input_num is zero */
+simdjson_inline int leading_zeroes(uint64_t input_num) {
+  return __builtin_clzll(input_num);
+}
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    if ((error = field_key().get(actual_key) )) { abandon(); return error; };
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value. It will also increment the depth by one.
-    if ((error = field_value() )) { abandon(); return error; }
+/* result might be undefined when input_num is zero */
+simdjson_inline int count_ones(uint64_t input_num) {
+  return __lasx_xvpickve2gr_w(__lasx_xvpcnt_d(__m256i(v4u64{input_num, 0, 0, 0})), 0);
+}
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
+  return __builtin_uaddll_overflow(value1, value2,
+                                   reinterpret_cast<unsigned long long *>(result));
+}
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
-  }
-  // Performance note: it maybe wasteful to rewind to the beginning when there might be
-  // no other query following. Indeed, it would require reskipping the whole object.
-  // Instead, you can just stay where you are. If there is a new query, there is always time
-  // to rewind.
-  if(at_first) { return false; }
+} // unnamed namespace
+} // namespace lasx
+} // namespace simdjson
 
-  // If we reach the end without finding a match, search the rest of the fields starting at the
-  // beginning of the object.
-  // (We have already run through the object before, so we've already validated its structure. We
-  // don't check errors in this bit.)
-  SIMDJSON_TRY(reset_object().get(has_value));
-  while (true) {
-    SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
-    SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
+#endif // SIMDJSON_LASX_BITMANIPULATION_H
+/* end file simdjson/lasx/bitmanipulation.h */
+/* including simdjson/lasx/bitmask.h: #include "simdjson/lasx/bitmask.h" */
+/* begin file simdjson/lasx/bitmask.h */
+#ifndef SIMDJSON_LASX_BITMASK_H
+#define SIMDJSON_LASX_BITMASK_H
 
-    // Get the key and colon, stopping at the value.
-    raw_json_string actual_key;
-    // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
-    // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
-    // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
-    // The depth is left unchanged by field_key().
-    error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
-    // field_value() will advance and check that we find a ':' separating the
-    // key and the value.  It will also increment the depth by one.
-    error = field_value(); SIMDJSON_ASSUME(!error);
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-    // If it matches, stop and return
-    // We could do it this way if we wanted to allow arbitrary
-    // key content (including escaped quotes).
-    // if (actual_key.unsafe_is_equal(max_key_length, key)) {
-    // Instead we do the following which may trigger buffer overruns if the
-    // user provides an adversarial key (containing a well placed unescaped quote
-    // character and being longer than the number of bytes remaining in the JSON
-    // input).
-    if (actual_key.unsafe_is_equal(key)) {
-      logger::log_event(*this, "match", key, -2);
-      // If we return here, then we return while pointing at the ':' that we just checked.
-      return true;
-    }
+namespace simdjson {
+namespace lasx {
+namespace {
 
-    // No match: skip the value and see if , or } is next
-    logger::log_event(*this, "no match", key, -2);
-    // The call to skip_child is meant to skip over the value corresponding to the key.
-    // After skip_child(), we are right before the next comma (',') or the final brace ('}').
-    SIMDJSON_TRY( skip_child() );
-    // If we reached the end of the key-value pair we started from, then we know
-    // that the key is not there so we return false. We are either right before
-    // the next comma or the final brace.
-    if(_json_iter->position() == search_start) { return false; }
-    // The has_next_field() advances the pointer and check that either ',' or '}' is found.
-    // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
-    // then we are in error and we abort.
-    error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
-    // If we make the mistake of exiting here, then we could be left pointing at a key
-    // in the middle of an object. That's not an allowable state.
-  }
-  // If the loop ended, we're out of fields to look at. The program should
-  // never reach this point.
-  return false;
+//
+// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
+//
+// For example, prefix_xor(00100100) == 00011100
+//
+simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
+  bitmask ^= bitmask << 1;
+  bitmask ^= bitmask << 2;
+  bitmask ^= bitmask << 4;
+  bitmask ^= bitmask << 8;
+  bitmask ^= bitmask << 16;
+  bitmask ^= bitmask << 32;
+  return bitmask;
 }
-SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
-  assert_at_next();
+} // unnamed namespace
+} // namespace lasx
+} // namespace simdjson
 
-  const uint8_t *key = _json_iter->return_current_and_advance();
-  if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
-  return raw_json_string(key);
-}
+#endif
+/* end file simdjson/lasx/bitmask.h */
+/* including simdjson/lasx/numberparsing_defs.h: #include "simdjson/lasx/numberparsing_defs.h" */
+/* begin file simdjson/lasx/numberparsing_defs.h */
+#ifndef SIMDJSON_LASX_NUMBERPARSING_DEFS_H
+#define SIMDJSON_LASX_NUMBERPARSING_DEFS_H
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
-  assert_at_next();
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/intrinsics.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
-  _json_iter->descend_to(depth()+1);
-  return SUCCESS;
-}
+#include <cstring>
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_array();
-}
+namespace simdjson {
+namespace lasx {
+namespace numberparsing {
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_root_array() noexcept {
-  SIMDJSON_TRY( start_container('[', "Not an array", "array") );
-  return started_root_array();
+// we don't have appropriate instructions, so let us use a scalar function
+// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+/** @private */
+static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
+  uint64_t val;
+  std::memcpy(&val, chars, sizeof(uint64_t));
+  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
+  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
 }
 
-inline std::string value_iterator::to_string() const noexcept {
-  auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
-  if(_json_iter != nullptr) { answer +=  _json_iter->to_string(); }
-  answer += std::string(" ]");
+simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
+  internal::value128 answer;
+  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
+  answer.low = uint64_t(r);
+  answer.high = uint64_t(r >> 64);
   return answer;
 }
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
-  assert_at_container_start();
-  if (*_json_iter->peek() == ']') {
-    logger::log_value(*_json_iter, "empty array");
-    _json_iter->return_current_and_advance();
-    SIMDJSON_TRY( end_container() );
-    return false;
-  }
-  _json_iter->descend_to(depth()+1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  _json_iter->set_start_position(_depth, start_position());
+} // namespace numberparsing
+} // namespace lasx
+} // namespace simdjson
+
+#ifndef SIMDJSON_SWAR_NUMBER_PARSING
+#if SIMDJSON_IS_BIG_ENDIAN
+#define SIMDJSON_SWAR_NUMBER_PARSING 0
+#else
+#define SIMDJSON_SWAR_NUMBER_PARSING 1
+#endif
 #endif
-  return true;
-}
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
-  // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
-  // current document. It only works in the normal mode where we have indexed a single document.
-  // Note that adding a check for 'streaming' is not expensive since we only have at most
-  // one root element.
-  if ( ! _json_iter->streaming() ) {
-    // The following lines do not fully protect against garbage content within the
-    // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
-    // also call `at_end()` on the document instance at the end of the processing to
-    // ensure that the processing has finished at the end.
-    //
-    if (*_json_iter->peek_last() != ']') {
-      _json_iter->abandon();
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
-    }
-    // If the last character is ] *and* the first gibberish character is also ']'
-    // then on-demand could accidentally go over. So we need additional checks.
-    // https://github.com/simdjson/simdjson/issues/1834
-    // Checking that the document is balanced requires a full scan which is potentially
-    // expensive, but it only happens in edge cases where the first padding character is
-    // a closing bracket.
-    if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
-      _json_iter->abandon();
-      // The exact error would require more work. It will typically be an unclosed array.
-      return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
-    }
-  }
-  return SUCCESS;
-}
-
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_root_array() noexcept {
-  auto error = check_root_array();
-  if (error) { return error; }
-  return started_array();
-}
+#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
+/* end file simdjson/lasx/numberparsing_defs.h */
+/* including simdjson/lasx/simd.h: #include "simdjson/lasx/simd.h" */
+/* begin file simdjson/lasx/simd.h */
+#ifndef SIMDJSON_LASX_SIMD_H
+#define SIMDJSON_LASX_SIMD_H
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_element() noexcept {
-  assert_at_next();
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  logger::log_event(*this, "has_next_element");
-  switch (*_json_iter->return_current_and_advance()) {
-    case ']':
-      logger::log_end_value(*_json_iter, "array");
-      SIMDJSON_TRY( end_container() );
-      return false;
-    case ',':
-      _json_iter->descend_to(depth()+1);
-      return true;
-    default:
-      return report_error(TAPE_ERROR, "Missing comma between array elements");
-  }
-}
+namespace simdjson {
+namespace lasx {
+namespace {
+namespace simd {
 
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
-  auto not_true = atomparsing::str4ncmp(json, "true");
-  auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
-  bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
-  if (error) { return incorrect_type_error("Not a boolean"); }
-  return simdjson_result<bool>(!not_true);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
-  bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
-  // if we start with 'n', we must be a null
-  if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
-  return is_null_string;
-}
+  // Forward-declared so they can be used by splat and friends.
+  template<typename Child>
+  struct base {
+    __m256i value;
 
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
-  return get_raw_json_string().unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_string(allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
-  return get_raw_json_string().unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
-  auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
-  auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
-  auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
-  auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
-  auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
-  auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
-  auto result = parse_bool(peek_non_root_scalar("bool"));
-  if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
-  bool is_null_value;
-  SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
-  if(is_null_value) { advance_non_root_scalar("null"); }
-  return is_null_value;
-}
-simdjson_inline bool value_iterator::is_negative() noexcept {
-  return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
-}
-simdjson_inline bool value_iterator::is_root_negative() noexcept {
-  return numberparsing::is_negative(peek_root_scalar("numbersign"));
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
-  return numberparsing::is_integer(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
-  return numberparsing::get_number_type(peek_non_root_scalar("integer"));
-}
-simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
-  number num;
-  error_code error =  numberparsing::parse_number(peek_non_root_scalar("number"), num);
-  if(error) { return error; }
-  return num;
-}
+    // Zero constructor
+    simdjson_inline base() : value{__m256i()} {}
 
-simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("is_root_integer");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    return false; // if there are more than 20 characters, it cannot be represented as an integer.
-  }
-  auto answer = numberparsing::is_integer(tmpbuf);
-  // If the parsing was a success, we must still check that it is
-  // a single scalar. Note that we parse first because of cases like '[]' where
-  // getting TRAILING_CONTENT is wrong.
-  if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
-  return answer;
-}
+    // Conversion from SIMD register
+    simdjson_inline base(const __m256i _value) : value(_value) {}
 
-simdjson_inline simdjson_result<lsx::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return number_type::big_integer;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  auto answer = numberparsing::get_number_type(tmpbuf);
-  if (check_trailing && (answer.error() == SUCCESS)  && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  return answer;
-}
-simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("number");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
-  uint8_t tmpbuf[1074+8+1+1];
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    if(numberparsing::check_if_integer(json, max_len)) {
-      if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-      logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
-      return BIGINT_ERROR;
-    }
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
-    return NUMBER_ERROR;
-  }
-  number num;
-  error_code error =  numberparsing::parse_number(tmpbuf, num);
-  if(error) { return error; }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_root_scalar("number");
-  return num;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
-}
-template <typename string_type>
-simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
-  std::string_view content;
-  auto err = get_root_string(check_trailing, allow_replacement).get(content);
-  if (err) { return err; }
-  receiver = content;
-  return SUCCESS;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-  return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
-}
-simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
-  auto json = peek_scalar("string");
-  if (*json != '"') { return incorrect_type_error("Not a string"); }
-  if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-  advance_scalar("string");
-  return raw_json_string(json+1);
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("uint64");
-  uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("uint64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+    // Conversion to SIMD register
+    simdjson_inline operator const __m256i&() const { return this->value; }
+    simdjson_inline operator __m256i&() { return this->value; }
+    simdjson_inline operator const v32i8&() const { return (v32i8&)this->value; }
+    simdjson_inline operator v32i8&() { return (v32i8&)this->value; }
 
-  auto result = numberparsing::parse_integer(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("int64");
-  uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
-  tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
-    return NUMBER_ERROR;
-  }
+    // Bit operations
+    simdjson_inline Child operator|(const Child other) const { return __lasx_xvor_v(*this, other); }
+    simdjson_inline Child operator&(const Child other) const { return __lasx_xvand_v(*this, other); }
+    simdjson_inline Child operator^(const Child other) const { return __lasx_xvxor_v(*this, other); }
+    simdjson_inline Child bit_andnot(const Child other) const { return __lasx_xvandn_v(other, *this); }
+    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
+    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
+    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
+  };
 
-  auto result = numberparsing::parse_integer_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("int64");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
+  // Forward-declared so they can be used by splat and friends.
+  template<typename T>
+  struct simd8;
 
-simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("double");
-  // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
-  // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
-  // number: -0.<fraction>e-308.
-  uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
-  tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
-    logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
-    return NUMBER_ERROR;
-  }
-  auto result = numberparsing::parse_double_in_string(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("double");
-  }
-  return result;
-}
-simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("bool");
-  uint8_t tmpbuf[5+1+1]; // +1 for null termination
-  tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
-  if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
-  auto result = parse_bool(tmpbuf);
-  if(result.error() == SUCCESS) {
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("bool");
-  }
-  return result;
-}
-simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
-  auto max_len = peek_root_length();
-  auto json = peek_root_scalar("null");
-  bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
-         (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
-  if(result) { // we have something that looks like a null.
-    if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
-    advance_root_scalar("null");
-  } else if (json[0] == 'n') {
-    return incorrect_type_error("Not a null but starts with n");
-  }
-  return result;
-}
+  template<typename T, typename Mask=simd8<bool>>
+  struct base8: base<simd8<T>> {
+    simdjson_inline base8() : base<simd8<T>>() {}
+    simdjson_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
 
-simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
+    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lasx_xvseq_b(lhs, rhs); }
 
-  return _json_iter->skip_child(depth());
-}
+    static const int SIZE = sizeof(base<simd8<T>>::value);
 
-simdjson_inline value_iterator value_iterator::child() const noexcept {
-  assert_at_child();
-  return { _json_iter, depth()+1, _json_iter->token.position() };
-}
+    template<int N=1>
+    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+        __m256i hi = __lasx_xvbsll_v(*this, N);
+        __m256i lo = __lasx_xvbsrl_v(*this, 16 - N);
+        __m256i tmp = __lasx_xvbsrl_v(prev_chunk, 16 - N);
+        lo = __lasx_xvpermi_q(lo, tmp, 0x21);
+        return __lasx_xvor_v(hi, lo);
+    }
+  };
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
-// marked non-inline.
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline bool value_iterator::is_open() const noexcept {
-  return _json_iter->depth() >= depth();
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+  // SIMD byte mask type (returned by things like eq and gt)
+  template<>
+  struct simd8<bool>: base8<bool> {
+    static simdjson_inline simd8<bool> splat(bool _value) { return __lasx_xvreplgr2vr_b(uint8_t(-(!!_value))); }
 
-simdjson_inline bool value_iterator::at_end() const noexcept {
-  return _json_iter->at_end();
-}
+    simdjson_inline simd8() : base8() {}
+    simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
 
-simdjson_inline bool value_iterator::at_start() const noexcept {
-  return _json_iter->token.position() == start_position();
-}
+    simdjson_inline int to_bitmask() const {
+      __m256i mask = __lasx_xvmskltz_b(*this);
+      return (__lasx_xvpickve2gr_w(mask, 4) << 16) | (__lasx_xvpickve2gr_w(mask, 0));
+    }
+   simdjson_inline bool any() const {
+      __m256i v = __lasx_xvmsknz_b(*this);
+      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
+    }
+    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
+  };
 
-simdjson_inline bool value_iterator::at_first_field() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  return _json_iter->token.position() == start_position() + 1;
-}
+  template<typename T>
+  struct base8_numeric: base8<T> {
+    static simdjson_inline simd8<T> splat(T _value) {
+      return __lasx_xvreplgr2vr_b(_value);
+    }
+    static simdjson_inline simd8<T> zero() { return __lasx_xvldi(0); }
+    static simdjson_inline simd8<T> load(const T values[32]) {
+      return __lasx_xvld(reinterpret_cast<const __m256i *>(values), 0);
+    }
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    static simdjson_inline simd8<T> repeat_16(
+      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
+      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
+    ) {
+      return simd8<T>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-simdjson_inline void value_iterator::abandon() noexcept {
-  _json_iter->abandon();
-}
+    simdjson_inline base8_numeric() : base8<T>() {}
+    simdjson_inline base8_numeric(const __m256i _value) : base8<T>(_value) {}
 
-simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
-  return _depth;
-}
-simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
-  return _json_iter->error;
-}
-simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
-  return _json_iter->string_buf_loc();
-}
-simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
-  return *_json_iter;
-}
-simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
-  return *_json_iter;
-}
+    // Store to array
+    simdjson_inline void store(T dst[32]) const {
+      return __lasx_xvst(*this, reinterpret_cast<__m256i *>(dst), 0);
+    }
 
-simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
-  return _json_iter->peek(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
-  return _json_iter->peek_length(start_position());
-}
-simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
-  return _json_iter->peek_root_length(start_position());
-}
+    // Addition/subtraction are the same for signed and unsigned
+    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lasx_xvadd_b(*this, other); }
+    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lasx_xvsub_b(*this, other); }
+    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
+    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
 
-simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return peek_start(); }
-
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  return _json_iter->peek();
-}
-
-simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  if (!is_at_start()) { return; }
-
-  // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
-  assert_at_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-
-simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
-  logger::log_start_value(*_json_iter, start_position(), depth(), type);
-  // If we're not at the position anymore, we don't want to advance the cursor.
-  const uint8_t *json;
-  if (!is_at_start()) {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-    if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-    json = peek_start();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-  } else {
-    assert_at_start();
-    /**
-     * We should be prudent. Let us peek. If it is not the right type, we
-     * return an error. Only once we have determined that we have the right
-     * type are we allowed to advance!
-     */
-    json = _json_iter->peek();
-    if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
-    _json_iter->return_current_and_advance();
-  }
-
-
-  return SUCCESS;
-}
-
-
-simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
-
-  assert_at_root();
-  return _json_iter->peek();
-}
-simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return peek_start(); }
-
-  assert_at_non_root_start();
-  return _json_iter->peek();
-}
-
-simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_root();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
-  logger::log_value(*_json_iter, start_position(), depth(), type);
-  if (!is_at_start()) { return; }
-
-  assert_at_non_root_start();
-  _json_iter->return_current_and_advance();
-  _json_iter->ascend_to(depth()-1);
-}
-
-simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
-  logger::log_error(*_json_iter, start_position(), depth(), message);
-  return INCORRECT_TYPE;
-}
-
-simdjson_inline bool value_iterator::is_at_start() const noexcept {
-  return position() == start_position();
-}
-
-simdjson_inline bool value_iterator::is_at_key() const noexcept {
-  // Keys are at the same depth as the object.
-  // Note here that we could be safer and check that we are within an object,
-  // but we do not.
-  return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
-}
-
-simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
-  // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
-  auto delta = position() - start_position();
-  return delta == 1 || delta == 2;
-}
-
-inline void value_iterator::assert_at_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-inline void value_iterator::assert_at_container_start() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-inline void value_iterator::assert_at_next() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-simdjson_inline void value_iterator::move_at_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position);
-}
-
-simdjson_inline void value_iterator::move_at_container_start() noexcept {
-  _json_iter->_depth = _depth;
-  _json_iter->token.set_position(_start_position + 1);
-}
-
-simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_array();
-}
-
-simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
-  if(error()) { return error(); }
-  move_at_container_start();
-  return started_object();
-}
-
-inline void value_iterator::assert_at_child() const noexcept {
-  SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
-  SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
-  SIMDJSON_ASSUME( _depth > 0 );
-}
-
-inline void value_iterator::assert_at_root() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth == 1 );
-}
-
-inline void value_iterator::assert_at_non_root_start() const noexcept {
-  assert_at_start();
-  SIMDJSON_ASSUME( _depth > 1 );
-}
-
-inline void value_iterator::assert_is_valid() const noexcept {
-  SIMDJSON_ASSUME( _json_iter != nullptr );
-}
-
-simdjson_inline bool value_iterator::is_valid() const noexcept {
-  return _json_iter != nullptr;
-}
-
-simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
-  switch (*peek_start()) {
-    case '{':
-      return json_type::object;
-    case '[':
-      return json_type::array;
-    case '"':
-      return json_type::string;
-    case 'n':
-      return json_type::null;
-    case 't': case 'f':
-      return json_type::boolean;
-    case '-':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-      return json_type::number;
-    default:
-      return TAPE_ERROR;
-  }
-}
-
-simdjson_inline token_position value_iterator::start_position() const noexcept {
-  return _start_position;
-}
-
-simdjson_inline token_position value_iterator::position() const noexcept {
-  return _json_iter->position();
-}
-
-simdjson_inline token_position value_iterator::end_position() const noexcept {
-  return _json_iter->end_position();
-}
-
-simdjson_inline token_position value_iterator::last_position() const noexcept {
-  return _json_iter->last_position();
-}
-
-simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
-  return _json_iter->report_error(error, message);
-}
-
-} // namespace ondemand
-} // namespace lsx
-} // namespace simdjson
-
-namespace simdjson {
-
-simdjson_inline simdjson_result<lsx::ondemand::value_iterator>::simdjson_result(lsx::ondemand::value_iterator &&value) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::value_iterator>(std::forward<lsx::ondemand::value_iterator>(value)) {}
-simdjson_inline simdjson_result<lsx::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
-    : implementation_simdjson_result_base<lsx::ondemand::value_iterator>(error) {}
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/value_iterator-inl.h for lsx */
-
-
-/* end file simdjson/generic/ondemand/amalgamated.h for lsx */
-/* including simdjson/lsx/end.h: #include "simdjson/lsx/end.h" */
-/* begin file simdjson/lsx/end.h */
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lsx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
-/* undefining SIMDJSON_IMPLEMENTATION from "lsx" */
-#undef SIMDJSON_IMPLEMENTATION
-/* end file simdjson/lsx/end.h */
-
-#endif // SIMDJSON_LSX_ONDEMAND_H
-/* end file simdjson/lsx/ondemand.h */
-#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
-/* including simdjson/lasx/ondemand.h: #include "simdjson/lasx/ondemand.h" */
-/* begin file simdjson/lasx/ondemand.h */
-#ifndef SIMDJSON_LASX_ONDEMAND_H
-#define SIMDJSON_LASX_ONDEMAND_H
-
-/* including simdjson/lasx/begin.h: #include "simdjson/lasx/begin.h" */
-/* begin file simdjson/lasx/begin.h */
-/* defining SIMDJSON_IMPLEMENTATION to "lasx" */
-#define SIMDJSON_IMPLEMENTATION lasx
-/* including simdjson/lasx/base.h: #include "simdjson/lasx/base.h" */
-/* begin file simdjson/lasx/base.h */
-#ifndef SIMDJSON_LASX_BASE_H
-#define SIMDJSON_LASX_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-/**
- * Implementation for LASX.
- */
-namespace lasx {
-
-class implementation;
-
-namespace {
-namespace simd {
-template <typename T> struct simd8;
-template <typename T> struct simd8x64;
-} // namespace simd
-} // unnamed namespace
-
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_LASX_BASE_H
-/* end file simdjson/lasx/base.h */
-/* including simdjson/lasx/intrinsics.h: #include "simdjson/lasx/intrinsics.h" */
-/* begin file simdjson/lasx/intrinsics.h */
-#ifndef SIMDJSON_LASX_INTRINSICS_H
-#define SIMDJSON_LASX_INTRINSICS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-// This should be the correct header whether
-// you use visual studio or other compilers.
-#include <lasxintrin.h>
-
-static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch ASX");
-
-#endif //  SIMDJSON_LASX_INTRINSICS_H
-/* end file simdjson/lasx/intrinsics.h */
-/* including simdjson/lasx/bitmanipulation.h: #include "simdjson/lasx/bitmanipulation.h" */
-/* begin file simdjson/lasx/bitmanipulation.h */
-#ifndef SIMDJSON_LASX_BITMANIPULATION_H
-#define SIMDJSON_LASX_BITMANIPULATION_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmask.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace {
-
-// We sometimes call trailing_zero on inputs that are zero,
-// but the algorithms do not end up using the returned value.
-// Sadly, sanitizers are not smart enough to figure it out.
-SIMDJSON_NO_SANITIZE_UNDEFINED
-// This function can be used safely even if not all bytes have been
-// initialized.
-// See issue https://github.com/simdjson/simdjson/issues/1965
-SIMDJSON_NO_SANITIZE_MEMORY
-simdjson_inline int trailing_zeroes(uint64_t input_num) {
-  return __builtin_ctzll(input_num);
-}
-
-/* result might be undefined when input_num is zero */
-simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
-  return input_num & (input_num-1);
-}
-
-/* result might be undefined when input_num is zero */
-simdjson_inline int leading_zeroes(uint64_t input_num) {
-  return __builtin_clzll(input_num);
-}
-
-/* result might be undefined when input_num is zero */
-simdjson_inline int count_ones(uint64_t input_num) {
-  return __lasx_xvpickve2gr_w(__lasx_xvpcnt_d(__m256i(v4u64{input_num, 0, 0, 0})), 0);
-}
-
-simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
-  return __builtin_uaddll_overflow(value1, value2,
-                                   reinterpret_cast<unsigned long long *>(result));
-}
-
-} // unnamed namespace
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_LASX_BITMANIPULATION_H
-/* end file simdjson/lasx/bitmanipulation.h */
-/* including simdjson/lasx/bitmask.h: #include "simdjson/lasx/bitmask.h" */
-/* begin file simdjson/lasx/bitmask.h */
-#ifndef SIMDJSON_LASX_BITMASK_H
-#define SIMDJSON_LASX_BITMASK_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace {
-
-//
-// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
-//
-// For example, prefix_xor(00100100) == 00011100
-//
-simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
-  bitmask ^= bitmask << 1;
-  bitmask ^= bitmask << 2;
-  bitmask ^= bitmask << 4;
-  bitmask ^= bitmask << 8;
-  bitmask ^= bitmask << 16;
-  bitmask ^= bitmask << 32;
-  return bitmask;
-}
-
-} // unnamed namespace
-} // namespace lasx
-} // namespace simdjson
-
-#endif
-/* end file simdjson/lasx/bitmask.h */
-/* including simdjson/lasx/numberparsing_defs.h: #include "simdjson/lasx/numberparsing_defs.h" */
-/* begin file simdjson/lasx/numberparsing_defs.h */
-#ifndef SIMDJSON_LASX_NUMBERPARSING_DEFS_H
-#define SIMDJSON_LASX_NUMBERPARSING_DEFS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/intrinsics.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <cstring>
-
-namespace simdjson {
-namespace lasx {
-namespace numberparsing {
-
-// we don't have appropriate instructions, so let us use a scalar function
-// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
-/** @private */
-static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
-  uint64_t val;
-  std::memcpy(&val, chars, sizeof(uint64_t));
-  val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
-  val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
-  return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
-}
-
-simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
-  internal::value128 answer;
-  __uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
-  answer.low = uint64_t(r);
-  answer.high = uint64_t(r >> 64);
-  return answer;
-}
-
-} // namespace numberparsing
-} // namespace lasx
-} // namespace simdjson
-
-#ifndef SIMDJSON_SWAR_NUMBER_PARSING
-#if SIMDJSON_IS_BIG_ENDIAN
-#define SIMDJSON_SWAR_NUMBER_PARSING 0
-#else
-#define SIMDJSON_SWAR_NUMBER_PARSING 1
-#endif
-#endif
-
-#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
-/* end file simdjson/lasx/numberparsing_defs.h */
-/* including simdjson/lasx/simd.h: #include "simdjson/lasx/simd.h" */
-/* begin file simdjson/lasx/simd.h */
-#ifndef SIMDJSON_LASX_SIMD_H
-#define SIMDJSON_LASX_SIMD_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace {
-namespace simd {
-
-  // Forward-declared so they can be used by splat and friends.
-  template<typename Child>
-  struct base {
-    __m256i value;
-
-    // Zero constructor
-    simdjson_inline base() : value{__m256i()} {}
-
-    // Conversion from SIMD register
-    simdjson_inline base(const __m256i _value) : value(_value) {}
-
-    // Conversion to SIMD register
-    simdjson_inline operator const __m256i&() const { return this->value; }
-    simdjson_inline operator __m256i&() { return this->value; }
-    simdjson_inline operator const v32i8&() const { return (v32i8&)this->value; }
-    simdjson_inline operator v32i8&() { return (v32i8&)this->value; }
-
-    // Bit operations
-    simdjson_inline Child operator|(const Child other) const { return __lasx_xvor_v(*this, other); }
-    simdjson_inline Child operator&(const Child other) const { return __lasx_xvand_v(*this, other); }
-    simdjson_inline Child operator^(const Child other) const { return __lasx_xvxor_v(*this, other); }
-    simdjson_inline Child bit_andnot(const Child other) const { return __lasx_xvandn_v(other, *this); }
-    simdjson_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
-    simdjson_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
-    simdjson_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
-  };
-
-  // Forward-declared so they can be used by splat and friends.
-  template<typename T>
-  struct simd8;
-
-  template<typename T, typename Mask=simd8<bool>>
-  struct base8: base<simd8<T>> {
-    simdjson_inline base8() : base<simd8<T>>() {}
-    simdjson_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
-
-    friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return __lasx_xvseq_b(lhs, rhs); }
-
-    static const int SIZE = sizeof(base<simd8<T>>::value);
-
-    template<int N=1>
-    simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
-        __m256i hi = __lasx_xvbsll_v(*this, N);
-        __m256i lo = __lasx_xvbsrl_v(*this, 16 - N);
-        __m256i tmp = __lasx_xvbsrl_v(prev_chunk, 16 - N);
-        lo = __lasx_xvpermi_q(lo, tmp, 0x21);
-        return __lasx_xvor_v(hi, lo);
-    }
-  };
-
-  // SIMD byte mask type (returned by things like eq and gt)
-  template<>
-  struct simd8<bool>: base8<bool> {
-    static simdjson_inline simd8<bool> splat(bool _value) { return __lasx_xvreplgr2vr_b(uint8_t(-(!!_value))); }
-
-    simdjson_inline simd8() : base8() {}
-    simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
-
-    simdjson_inline int to_bitmask() const {
-      __m256i mask = __lasx_xvmskltz_b(*this);
-      return (__lasx_xvpickve2gr_w(mask, 4) << 16) | (__lasx_xvpickve2gr_w(mask, 0));
-    }
-   simdjson_inline bool any() const {
-      __m256i v = __lasx_xvmsknz_b(*this);
-      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
-    }
-    simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
-  };
-
-  template<typename T>
-  struct base8_numeric: base8<T> {
-    static simdjson_inline simd8<T> splat(T _value) {
-      return __lasx_xvreplgr2vr_b(_value);
-    }
-    static simdjson_inline simd8<T> zero() { return __lasx_xvldi(0); }
-    static simdjson_inline simd8<T> load(const T values[32]) {
-      return __lasx_xvld(reinterpret_cast<const __m256i *>(values), 0);
-    }
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    static simdjson_inline simd8<T> repeat_16(
-      T v0,  T v1,  T v2,  T v3,  T v4,  T v5,  T v6,  T v7,
-      T v8,  T v9,  T v10, T v11, T v12, T v13, T v14, T v15
-    ) {
-      return simd8<T>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
-
-    simdjson_inline base8_numeric() : base8<T>() {}
-    simdjson_inline base8_numeric(const __m256i _value) : base8<T>(_value) {}
-
-    // Store to array
-    simdjson_inline void store(T dst[32]) const {
-      return __lasx_xvst(*this, reinterpret_cast<__m256i *>(dst), 0);
-    }
-
-    // Addition/subtraction are the same for signed and unsigned
-    simdjson_inline simd8<T> operator+(const simd8<T> other) const { return __lasx_xvadd_b(*this, other); }
-    simdjson_inline simd8<T> operator-(const simd8<T> other) const { return __lasx_xvsub_b(*this, other); }
-    simdjson_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
-    simdjson_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
-
-    // Override to distinguish from bool version
-    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
-
-    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
-      return __lasx_xvshuf_b(lookup_table, lookup_table, *this);
-    }
-
-    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
-    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
-    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
-    // get written.
-    template<typename L>
-    simdjson_inline void compress(uint32_t mask, L * output) const {
-      using internal::thintable_epi8;
-      using internal::BitsSetTable256mul2;
-      using internal::pshufb_combine_table;
-      // this particular implementation was inspired by haswell
-      // lasx do it in 4 steps, first 8 bytes and then second 8 bytes...
-      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
-      uint8_t mask2 = uint8_t(mask >> 8); // second significant 8 bits
-      uint8_t mask3 = uint8_t(mask >> 16); // ...
-      uint8_t mask4 = uint8_t(mask >> 24); // ...
-      // next line just loads the 64-bit values thintable_epi8[mask{1,2,3,4}]
-      // into a 256-bit register.
-      __m256i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808, int64_t(thintable_epi8[mask3]), int64_t(thintable_epi8[mask4]) + 0x0808080808080808};
-      // this is the version "nearly pruned"
-      __m256i pruned = __lasx_xvshuf_b(*this, *this, shufmask);
-      // we still need to put the  pieces back together.
-      // we compute the popcount of the first words:
-      int pop1 = BitsSetTable256mul2[mask1];
-      int pop2 = BitsSetTable256mul2[mask2];
-      int pop3 = BitsSetTable256mul2[mask3];
-
-      // then load the corresponding mask
-      __m256i masklo = __lasx_xvldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
-      __m256i maskhi = __lasx_xvldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop3 * 8);
-      __m256i compactmask = __lasx_xvpermi_q(maskhi, masklo, 0x20);
-      __m256i answer = __lasx_xvshuf_b(pruned, pruned, compactmask);
-      __lasx_xvst(answer, reinterpret_cast<uint8_t*>(output), 0);
-      uint64_t value3 = __lasx_xvpickve2gr_du(answer, 2);
-      uint64_t value4 = __lasx_xvpickve2gr_du(answer, 3);
-      uint64_t *pos = reinterpret_cast<uint64_t*>(reinterpret_cast<uint8_t*>(output) + 16 - (pop1 + pop2) / 2);
-      pos[0] = value3;
-      pos[1] = value4;
-    }
-
-    template<typename L>
-    simdjson_inline simd8<L> lookup_16(
-        L replace0,  L replace1,  L replace2,  L replace3,
-        L replace4,  L replace5,  L replace6,  L replace7,
-        L replace8,  L replace9,  L replace10, L replace11,
-        L replace12, L replace13, L replace14, L replace15) const {
-      return lookup_16(simd8<L>::repeat_16(
-        replace0,  replace1,  replace2,  replace3,
-        replace4,  replace5,  replace6,  replace7,
-        replace8,  replace9,  replace10, replace11,
-        replace12, replace13, replace14, replace15
-      ));
-    }
-  };
-
-  // Signed bytes
-  template<>
-  struct simd8<int8_t> : base8_numeric<int8_t> {
-    simdjson_inline simd8() : base8_numeric<int8_t>() {}
-    simdjson_inline simd8(const __m256i _value) : base8_numeric<int8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const int8_t values[32]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15,
-      int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
-      int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31
-    ) : simd8({
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15,
-      v16,v17,v18,v19,v20,v21,v22,v23,
-      v24,v25,v26,v27,v28,v29,v30,v31
-      }) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<int8_t> repeat_16(
-      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
-      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
-    ) {
-      return simd8<int8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
-
-    // Order-sensitive comparisons
-    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lasx_xvmax_b(*this, other); }
-    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lasx_xvmin_b(*this, other); }
-    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lasx_xvslt_b(other, *this); }
-    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lasx_xvslt_b(*this, other); }
-  };
-
-  // Unsigned bytes
-  template<>
-  struct simd8<uint8_t>: base8_numeric<uint8_t> {
-    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
-    simdjson_inline simd8(const __m256i _value) : base8_numeric<uint8_t>(_value) {}
-    // Splat constructor
-    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
-    // Array constructor
-    simdjson_inline simd8(const uint8_t values[32]) : simd8(load(values)) {}
-    // Member-by-member initialization
-    simdjson_inline simd8(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15,
-      uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
-      uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31
-    ) : simd8(__m256i(v32u8{
-      v0, v1, v2, v3, v4, v5, v6, v7,
-      v8, v9, v10,v11,v12,v13,v14,v15,
-      v16,v17,v18,v19,v20,v21,v22,v23,
-      v24,v25,v26,v27,v28,v29,v30,v31
-    })) {}
-    // Repeat 16 values as many times as necessary (usually for lookup tables)
-    simdjson_inline static simd8<uint8_t> repeat_16(
-      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
-      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
-    ) {
-      return simd8<uint8_t>(
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15,
-        v0, v1, v2, v3, v4, v5, v6, v7,
-        v8, v9, v10,v11,v12,v13,v14,v15
-      );
-    }
-
-    // Saturated math
-    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lasx_xvsadd_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lasx_xvssub_bu(*this, other); }
-
-    // Order-specific operations
-    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lasx_xvmax_bu(*this, other); }
-    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lasx_xvmin_bu(other, *this); }
-    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
-    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
-    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
-    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
-    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
-    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
-
-    // Bit-specific operations
-    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
-    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
-    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
-    simdjson_inline bool is_ascii() const {
-      __m256i mask = __lasx_xvmskltz_b(*this);
-      return (0 == __lasx_xvpickve2gr_w(mask, 0)) && (0 == __lasx_xvpickve2gr_w(mask, 4));
-    }
-    simdjson_inline bool bits_not_set_anywhere() const {
-      __m256i v = __lasx_xvmsknz_b(*this);
-      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
-    }
-    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
-    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
-      __m256i v = __lasx_xvmsknz_b(__lasx_xvand_v(*this, bits));
-      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
-    }
-    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lasx_xvsrli_b(*this, N)); }
-    template<int N>
-    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lasx_xvslli_b(*this, N)); }
-  };
-
-  template<typename T>
-  struct simd8x64 {
-    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
-    static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block.");
-    const simd8<T> chunks[NUM_CHUNKS];
-
-    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
-    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
-    simd8x64() = delete; // no default constructor allowed
-
-    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
-    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+32)} {}
-
-    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
-      uint32_t mask1 = uint32_t(mask);
-      uint32_t mask2 = uint32_t(mask >> 32);
-      __m256i zcnt = __lasx_xvpcnt_w(__m256i(v4u64{~mask, 0, 0, 0}));
-      uint64_t zcnt1 = __lasx_xvpickve2gr_wu(zcnt, 0);
-      uint64_t zcnt2 = __lasx_xvpickve2gr_wu(zcnt, 1);
-      // There should be a critical value which processes in scaler is faster.
-      if (zcnt1)
-        this->chunks[0].compress(mask1, output);
-      if (zcnt2)
-        this->chunks[1].compress(mask2, output + zcnt1);
-      return zcnt1 + zcnt2;
-    }
-
-    simdjson_inline void store(T ptr[64]) const {
-      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
-      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
-    }
-
-    simdjson_inline uint64_t to_bitmask() const {
-      __m256i mask0 = __lasx_xvmskltz_b(this->chunks[0]);
-      __m256i mask1 = __lasx_xvmskltz_b(this->chunks[1]);
-      __m256i mask_tmp = __lasx_xvpickve_w(mask0, 4);
-      __m256i tmp = __lasx_xvpickve_w(mask1, 4);
-      mask0 = __lasx_xvinsve0_w(mask0, mask1, 1);
-      mask_tmp = __lasx_xvinsve0_w(mask_tmp, tmp, 1);
-      return __lasx_xvpickve2gr_du(__lasx_xvpackev_h(mask_tmp, mask0), 0);
-    }
-
-    simdjson_inline simd8<T> reduce_or() const {
-      return this->chunks[0] | this->chunks[1];
-    }
-
-    simdjson_inline uint64_t eq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] == mask,
-        this->chunks[1] == mask
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
-      return  simd8x64<bool>(
-        this->chunks[0] == other.chunks[0],
-        this->chunks[1] == other.chunks[1]
-      ).to_bitmask();
-    }
-
-    simdjson_inline uint64_t lteq(const T m) const {
-      const simd8<T> mask = simd8<T>::splat(m);
-      return  simd8x64<bool>(
-        this->chunks[0] <= mask,
-        this->chunks[1] <= mask
-      ).to_bitmask();
-    }
-  }; // struct simd8x64<T>
-
-} // namespace simd
-} // unnamed namespace
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_LASX_SIMD_H
-/* end file simdjson/lasx/simd.h */
-/* including simdjson/lasx/stringparsing_defs.h: #include "simdjson/lasx/stringparsing_defs.h" */
-/* begin file simdjson/lasx/stringparsing_defs.h */
-#ifndef SIMDJSON_LASX_STRINGPARSING_DEFS_H
-#define SIMDJSON_LASX_STRINGPARSING_DEFS_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/simd.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmanipulation.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace {
-
-using namespace simd;
-
-// Holds backslashes and quotes locations.
-struct backslash_and_quote {
-public:
-  static constexpr uint32_t BYTES_PROCESSED = 32;
-  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
-
-  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
-  simdjson_inline bool has_backslash() { return bs_bits != 0; }
-  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
-  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
-
-  uint32_t bs_bits;
-  uint32_t quote_bits;
-}; // struct backslash_and_quote
-
-simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
-  // this can read up to 31 bytes beyond the buffer size, but we require
-  // SIMDJSON_PADDING of padding
-  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
-  simd8<uint8_t> v(src);
-  v.store(dst);
-  return {
-      static_cast<uint32_t>((v == '\\').to_bitmask()),     // bs_bits
-      static_cast<uint32_t>((v == '"').to_bitmask()), // quote_bits
-  };
-}
-
-} // unnamed namespace
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_LASX_STRINGPARSING_DEFS_H
-/* end file simdjson/lasx/stringparsing_defs.h */
-
-#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
-/* end file simdjson/lasx/begin.h */
-/* including simdjson/generic/ondemand/amalgamated.h for lasx: #include "simdjson/generic/ondemand/amalgamated.h" */
-/* begin file simdjson/generic/ondemand/amalgamated.h for lasx */
-#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
-#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
-#endif
-
-// Stuff other things depend on
-/* including simdjson/generic/ondemand/base.h for lasx: #include "simdjson/generic/ondemand/base.h" */
-/* begin file simdjson/generic/ondemand/base.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-/**
- * A fast, simple, DOM-like interface that parses JSON as you use it.
- *
- * Designed for maximum speed and a lower memory profile.
- */
-namespace ondemand {
-
-/** Represents the depth of a JSON value (number of nested arrays/objects). */
-using depth_t = int32_t;
-
-/** @copydoc simdjson::lasx::number_type */
-using number_type = simdjson::lasx::number_type;
-
-/** @private Position in the JSON buffer indexes */
-using token_position = const uint32_t *;
-
-class array;
-class array_iterator;
-class document;
-class document_reference;
-class document_stream;
-class field;
-class json_iterator;
-enum class json_type;
-struct number;
-class object;
-class object_iterator;
-class parser;
-class raw_json_string;
-class token_iterator;
-class value;
-class value_iterator;
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
-/* end file simdjson/generic/ondemand/base.h for lasx */
-/* including simdjson/generic/ondemand/deserialize.h for lasx: #include "simdjson/generic/ondemand/deserialize.h" */
-/* begin file simdjson/generic/ondemand/deserialize.h for lasx */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <concepts>
-namespace simdjson {
-
-namespace tag_invoke_fn_ns {
-void tag_invoke();
-
-struct tag_invoke_fn {
-  template <typename Tag, typename... Args>
-    requires requires(Tag tag, Args &&...args) {
-      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-    }
-  constexpr auto operator()(Tag tag, Args &&...args) const
-      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
-                                   std::forward<Args>(args)...)))
-          -> decltype(tag_invoke(std::forward<Tag>(tag),
-                                 std::forward<Args>(args)...)) {
-    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-  }
-};
-} // namespace tag_invoke_fn_ns
-
-inline namespace tag_invoke_ns {
-inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
-} // namespace tag_invoke_ns
-
-template <typename Tag, typename... Args>
-concept tag_invocable = requires(Tag tag, Args... args) {
-  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
-};
-
-template <typename Tag, typename... Args>
-concept nothrow_tag_invocable =
-    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
-      {
-        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
-      } noexcept;
-    };
-
-template <typename Tag, typename... Args>
-using tag_invoke_result =
-    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
-
-template <typename Tag, typename... Args>
-using tag_invoke_result_t =
-    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
-
-template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
-
-
-struct deserialize_tag;
-
-/// These types are deserializable in a built-in way
-template <typename> struct is_builtin_deserializable : std::false_type {};
-template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
-template <> struct is_builtin_deserializable<double> : std::true_type {};
-template <> struct is_builtin_deserializable<bool> : std::true_type {};
-template <> struct is_builtin_deserializable<lasx::ondemand::array> : std::true_type {};
-template <> struct is_builtin_deserializable<lasx::ondemand::object> : std::true_type {};
-template <> struct is_builtin_deserializable<lasx::ondemand::value> : std::true_type {};
-template <> struct is_builtin_deserializable<lasx::ondemand::raw_json_string> : std::true_type {};
-template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
-
-template <typename T>
-concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
-
-template <typename T, typename ValT = lasx::ondemand::value>
-concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
-
-template <typename T, typename ValT = lasx::ondemand::value>
-concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-template <typename T, typename ValT = lasx::ondemand::value>
-concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
-
-// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
-template <typename T, typename ValT = lasx::ondemand::value>
-concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
-
-/// Deserialize Tag
-inline constexpr struct deserialize_tag {
-  using value_type = lasx::ondemand::value;
-  using document_type = lasx::ondemand::document;
-  using document_reference_type = lasx::ondemand::document_reference;
-
-  // Customization Point for value
-  template <typename T>
-    requires custom_deserializable<T, value_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document
-  template <typename T>
-    requires custom_deserializable<T, document_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-  // Customization Point for document reference
-  template <typename T>
-    requires custom_deserializable<T, document_reference_type>
-  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
-    return tag_invoke(*this, object, output);
-  }
-
-
-} deserialize{};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-
-/* end file simdjson/generic/ondemand/deserialize.h for lasx */
-/* including simdjson/generic/ondemand/value_iterator.h for lasx: #include "simdjson/generic/ondemand/value_iterator.h" */
-/* begin file simdjson/generic/ondemand/value_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-/**
- * Iterates through a single JSON value at a particular depth.
- *
- * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
- * the caller to call the right ones.
- *
- * @private This is not intended for external use.
- */
-class value_iterator {
-protected:
-  /** The underlying JSON iterator */
-  json_iterator *_json_iter{};
-  /** The depth of this value */
-  depth_t _depth{};
-  /**
-   * The starting token index for this value
-   */
-  token_position _start_position{};
-
-public:
-  simdjson_inline value_iterator() noexcept = default;
-
-  /**
-   * Denote that we're starting a document.
-   */
-  simdjson_inline void start_document() noexcept;
-
-  /**
-   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
-   *
-   * Optimized for scalars.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
-
-  /**
-   * Tell whether the iterator is at the EOF mark
-   */
-  simdjson_inline bool at_end() const noexcept;
-
-  /**
-   * Tell whether the iterator is at the start of the value
-   */
-  simdjson_inline bool at_start() const noexcept;
-
-  /**
-   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
-   */
-  simdjson_inline bool is_open() const noexcept;
-
-  /**
-   * Tell whether the value is at an object's first field (just after the {).
-   */
-  simdjson_inline bool at_first_field() const noexcept;
-
-  /**
-   * Abandon all iteration.
-   */
-  simdjson_inline void abandon() noexcept;
-
-  /**
-   * Get the child value as a value_iterator.
-   */
-  simdjson_inline value_iterator child_value() const noexcept;
-
-  /**
-   * Get the depth of this value.
-   */
-  simdjson_inline int32_t depth() const noexcept;
-
-  /**
-   * Get the JSON type of this value.
-   *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() const noexcept;
-
-  /**
-   * @addtogroup object Object iteration
-   *
-   * Methods to iterate and find object fields. These methods generally *assume* the value is
-   * actually an object; the caller is responsible for keeping track of that fact.
-   *
-   * @{
-   */
-
-  /**
-   * Start an object iteration.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
-  /**
-   * Start an object iteration from the root.
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
-  /**
-   * Checks whether an object could be started from the root. May be called by start_root_object.
-   *
-   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
-   * @error INCORRECT_TYPE if there is no opening {
-   * @error TAPE_ERROR if there is no matching } at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
-  /**
-   * Start an object iteration after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
-  /**
-   * Start an object iteration from the root, after the user has already checked and moved past the {.
-   *
-   * Does not move the iterator unless the object is empty ({}).
-   *
-   * @returns Whether the object had any fields (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
-
-  /**
-   * Moves to the next field in an object.
-   *
-   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return whether there is another field in the object.
-   * @error TAPE_ERROR If there is a comma missing between fields.
-   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
-
-  /**
-   * Get the current field's key.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
-
-  /**
-   * Pass the : in the field and move to its value.
-   */
-  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
-
-  /**
-   * Find the next field with the given key.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
-
-  /**
-   * Find the next field with the given key, *without* unescaping. This assumes object order: it
-   * will not find the field if it was already passed when looking for some *other* field.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
-
-  /**
-   * Find the field with the given key without regard to order, and *without* unescaping.
-   *
-   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
-   *
-   * Assumes you have called next_field() or otherwise matched the previous value.
-   *
-   * This means the iterator must be sitting at the next key:
-   *
-   * ```
-   * { "a": 1, "b": 2 }
-   *           ^
-   * ```
-   *
-   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
-   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
-   * fail to match some keys with escapes (\u, \n, etc.).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
-
-  /** @} */
-
-  /**
-   * @addtogroup array Array iteration
-   * Methods to iterate over array elements. These methods generally *assume* the value is actually
-   * an object; the caller is responsible for keeping track of that fact.
-   * @{
-   */
-
-  /**
-   * Check for an opening [ and start an array iteration.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
-  /**
-   * Check for an opening [ and start an array iteration while at the root.
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
-  /**
-   * Checks whether an array could be started from the root. May be called by start_root_array.
-   *
-   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
-   * @error INCORRECT_TYPE If there is no [.
-   * @error TAPE_ERROR if there is no matching ] at end of document
-   */
-  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
-  /**
-   * Start an array iteration, after the user has already checked and moved past the [.
-   *
-   * Does not move the iterator unless the array is empty ([]).
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
-  /**
-   * Start an array iteration from the root, after the user has already checked and moved past the [.
-   *
-   * Does not move the iterator unless the array is empty ([]).
-   *
-   * @returns Whether the array had any elements (returns false for empty).
-   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
-   *        array or object is incomplete).
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
-
-  /**
-   * Moves to the next element in an array.
-   *
-   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
-   * Otherwise, it advances to the next value.
-   *
-   * @return Whether there is another element in the array.
-   * @error TAPE_ERROR If there is a comma missing between elements.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
-
-  /**
-   * Get a child value iterator.
-   */
-  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
-
-  /** @} */
-
-  /**
-   * @defgroup scalar Scalar values
-   * @addtogroup scalar
-   * @{
-   */
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
-  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
-  template <typename string_type>
-  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
-  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
-
-  simdjson_inline error_code error() const noexcept;
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
-  simdjson_inline const json_iterator &json_iter() const noexcept;
-  simdjson_inline json_iterator &json_iter() noexcept;
-
-  simdjson_inline void assert_is_valid() const noexcept;
-  simdjson_inline bool is_valid() const noexcept;
-
-  /** @} */
-protected:
-  /**
-   * Restarts an array iteration.
-   * @returns Whether the array has any elements (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_array() noexcept;
-  /**
-   * Restarts an object iteration.
-   * @returns Whether the object has any fields (returns false for empty).
-   */
-  simdjson_inline simdjson_result<bool> reset_object() noexcept;
-  /**
-   * move_at_start(): moves us so that we are pointing at the beginning of
-   * the container. It updates the index so that at_start() is true and it
-   * syncs the depth. The user can then create a new container instance.
-   *
-   * Usage: used with value::count_elements().
-   **/
-  simdjson_inline void move_at_start() noexcept;
-
-  /**
-   * move_at_container_start(): moves us so that we are pointing at the beginning of
-   * the container so that assert_at_container_start() passes.
-   *
-   * Usage: used with reset_array() and reset_object().
-   **/
-   simdjson_inline void move_at_container_start() noexcept;
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
-
-  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
-  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
-  simdjson_inline const uint8_t *peek_start() const noexcept;
-  simdjson_inline uint32_t peek_start_length() const noexcept;
-  simdjson_inline uint32_t peek_root_length() const noexcept;
-
-  /**
-   * The general idea of the advance_... methods and the peek_* methods
-   * is that you first peek and check that you have desired type. If you do,
-   * and only if you do, then you advance.
-   *
-   * We used to unconditionally advance. But this made reasoning about our
-   * current state difficult.
-   * Suppose you always advance. Look at the 'value' matching the key
-   * "shadowable" in the following example...
-   *
-   * ({"globals":{"a":{"shadowable":[}}}})
-   *
-   * If the user thinks it is a Boolean and asks for it, then we check the '[',
-   * decide it is not a Boolean, but still move into the next character ('}'). Now
-   * we are left pointing at '}' right after a '['. And we have not yet reported
-   * an error, only that we do not have a Boolean.
-   *
-   * If, instead, you just stand your ground until it is content that you know, then
-   * you will only even move beyond the '[' if the user tells you that you have an
-   * array. So you will be at the '}' character inside the array and, hopefully, you
-   * will then catch the error because an array cannot start with '}', but the code
-   * processing Boolean values does not know this.
-   *
-   * So the contract is: first call 'peek_...' and then call 'advance_...' only
-   * if you have determined that it is a type you can handle.
-   *
-   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
-   */
-
-  simdjson_inline void advance_scalar(const char *type) noexcept;
-  simdjson_inline void advance_root_scalar(const char *type) noexcept;
-  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
-
-  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
-  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
-
-
-  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
-  simdjson_inline error_code end_container() noexcept;
-
-  /**
-   * Advance to a place expecting a value (increasing depth).
-   *
-   * @return The current token (the one left behind).
-   * @error TAPE_ERROR If the document ended early.
-   */
-  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
-
-  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
-  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
-
-  simdjson_inline bool is_at_start() const noexcept;
-  /**
-   * is_at_iterator_start() returns true on an array or object after it has just been
-   * created, whether the instance is empty or not.
-   *
-   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
-   */
-  simdjson_inline bool is_at_iterator_start() const noexcept;
-
-  /**
-   * Assuming that we are within an object, this returns true if we
-   * are pointing at a key.
-   *
-   * Usage: the skip_child() method should never be used while we are pointing
-   * at a key inside an object.
-   */
-  simdjson_inline bool is_at_key() const noexcept;
-
-  inline void assert_at_start() const noexcept;
-  inline void assert_at_container_start() const noexcept;
-  inline void assert_at_root() const noexcept;
-  inline void assert_at_child() const noexcept;
-  inline void assert_at_next() const noexcept;
-  inline void assert_at_non_root_start() const noexcept;
-
-  /** Get the starting position of this value */
-  simdjson_inline token_position start_position() const noexcept;
-
-  /** @copydoc error_code json_iterator::position() const noexcept; */
-  simdjson_inline token_position position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position last_position() const noexcept;
-  /** @copydoc error_code json_iterator::end_position() const noexcept; */
-  simdjson_inline token_position end_position() const noexcept;
-  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
-  friend class document;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class field;
-}; // value_iterator
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::value_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value_iterator> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::value_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
-/* end file simdjson/generic/ondemand/value_iterator.h for lasx */
-/* including simdjson/generic/ondemand/value.h for lasx: #include "simdjson/generic/ondemand/value.h" */
-/* begin file simdjson/generic/ondemand/value.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <type_traits>
-
-namespace simdjson {
-
-namespace lasx {
-namespace ondemand {
-/**
- * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
- * not access more data in the JSON document.
- */
-class value {
-public:
-  /**
-   * Create a new invalid value.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline value() noexcept = default;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get()
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template <typename T>
-  simdjson_inline error_code get(T &out)
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
-#else
-    noexcept
-#endif
- {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, value>) {
-      return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() noexcept;
-
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() noexcept;
-
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a unsigned integer.
-   *
-   * @returns A unsigned 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * In some instances, you may want to allow replacement of invalid Unicode sequences.
-   * You may do so by passing the allow_replacement parameter as true. In the following
-   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
-   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
-   * replacement character (U+FFFD).
-   *
-   *   simdjson::ondemand::parser parser;
-   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
-   *   simdjson::ondemand::document doc = parser.iterate(json);
-   *   auto view = doc["deviceId"].get_string(true);
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-
-  /**
-   * Cast this JSON value to a "wobbly" string.
-   *
-   * The string is may not be a valid UTF-8 string.
-   * See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
-   * is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-
-  /**
-   * Checks if this JSON value is null. If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-#if SIMDJSON_EXCEPTIONS
-  /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
-   *
-   * @returns An instance of type T
-   */
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() noexcept(false);
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
-   */
-  simdjson_inline operator object() noexcept(false);
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline operator uint64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline operator double() noexcept(false);
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Equivalent to get<std::string_view>().
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator std::string_view() noexcept(false);
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
-   */
-  simdjson_inline operator raw_json_string() noexcept(false);
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
-   */
-  simdjson_inline operator bool() noexcept(false);
-#endif
-
-  /**
-   * Begin array iteration.
-   *
-   * Part of the std::iterable interface.
-   *
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  /**
-   * Sentinel representing the end of the array.
-   *
-   * Part of the std::iterable interface.
-   */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * Performance hint: You should only call count_elements() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method on the object instance.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
-   *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
-   */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
+    // Override to distinguish from bool version
+    simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
 
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
-  simdjson_result<value> operator[](int) noexcept = delete;
+    // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
+      return __lasx_xvshuf_b(lookup_table, lookup_table, *this);
+    }
 
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   *
-   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
-   *     json_type::number, json_type::boolean, or json_type::null).
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
+    // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
+    // Passing a 0 value for mask would be equivalent to writing out every byte to output.
+    // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
+    // get written.
+    template<typename L>
+    simdjson_inline void compress(uint32_t mask, L * output) const {
+      using internal::thintable_epi8;
+      using internal::BitsSetTable256mul2;
+      using internal::pshufb_combine_table;
+      // this particular implementation was inspired by haswell
+      // lasx do it in 4 steps, first 8 bytes and then second 8 bytes...
+      uint8_t mask1 = uint8_t(mask); // least significant 8 bits
+      uint8_t mask2 = uint8_t(mask >> 8); // second significant 8 bits
+      uint8_t mask3 = uint8_t(mask >> 16); // ...
+      uint8_t mask4 = uint8_t(mask >> 24); // ...
+      // next line just loads the 64-bit values thintable_epi8[mask{1,2,3,4}]
+      // into a 256-bit register.
+      __m256i shufmask = {int64_t(thintable_epi8[mask1]), int64_t(thintable_epi8[mask2]) + 0x0808080808080808, int64_t(thintable_epi8[mask3]), int64_t(thintable_epi8[mask4]) + 0x0808080808080808};
+      // this is the version "nearly pruned"
+      __m256i pruned = __lasx_xvshuf_b(*this, *this, shufmask);
+      // we still need to put the  pieces back together.
+      // we compute the popcount of the first words:
+      int pop1 = BitsSetTable256mul2[mask1];
+      int pop2 = BitsSetTable256mul2[mask2];
+      int pop3 = BitsSetTable256mul2[mask3];
 
-  /**
-   * Checks whether the value is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
-   *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  /**
-   * Checks whether the value is a string.
-   *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+      // then load the corresponding mask
+      __m256i masklo = __lasx_xvldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop1 * 8);
+      __m256i maskhi = __lasx_xvldx(reinterpret_cast<void*>(reinterpret_cast<unsigned long>(pshufb_combine_table)), pop3 * 8);
+      __m256i compactmask = __lasx_xvpermi_q(maskhi, masklo, 0x20);
+      __m256i answer = __lasx_xvshuf_b(pruned, pruned, compactmask);
+      __lasx_xvst(answer, reinterpret_cast<uint8_t*>(output), 0);
+      uint64_t value3 = __lasx_xvpickve2gr_du(answer, 2);
+      uint64_t value4 = __lasx_xvpickve2gr_du(answer, 3);
+      uint64_t *pos = reinterpret_cast<uint64_t*>(reinterpret_cast<uint8_t*>(output) + 16 - (pop1 + pop2) / 2);
+      pos[0] = value3;
+      pos[1] = value4;
+    }
 
-  /**
-   * Checks whether the value is a negative number.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the value is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
-   *
-   * Performance note: if you call this function systematically
-   * before parsing a number, you may have fallen for a performance
-   * anti-pattern.
-   *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
-   *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
-   *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808.
-   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
-   * in which case the digit_count is set to the length of the big integer string.
-   * Otherwise, get_number_type() has value number_type::floating_point_number.
-   *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
-   *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+    template<typename L>
+    simdjson_inline simd8<L> lookup_16(
+        L replace0,  L replace1,  L replace2,  L replace3,
+        L replace4,  L replace5,  L replace6,  L replace7,
+        L replace8,  L replace9,  L replace10, L replace11,
+        L replace12, L replace13, L replace14, L replace15) const {
+      return lookup_16(simd8<L>::repeat_16(
+        replace0,  replace1,  replace2,  replace3,
+        replace4,  replace5,  replace6,  replace7,
+        replace8,  replace9,  replace10, replace11,
+        replace12, replace13, replace14, replace15
+      ));
+    }
+  };
 
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
-   *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
-   *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
-   *
-   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
-   *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
-   *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   *
-   * Performance note: this is designed with performance in mind. When
-   * calling 'get_number()', you scan the number string only once, determining
-   * efficiently the type and storing it in an efficient manner.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+  // Signed bytes
+  template<>
+  struct simd8<int8_t> : base8_numeric<int8_t> {
+    simdjson_inline simd8() : base8_numeric<int8_t>() {}
+    simdjson_inline simd8(const __m256i _value) : base8_numeric<int8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const int8_t values[32]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15,
+      int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
+      int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31
+    ) : simd8({
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15,
+      v16,v17,v18,v19,v20,v21,v22,v23,
+      v24,v25,v26,v27,v28,v29,v30,v31
+      }) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<int8_t> repeat_16(
+      int8_t v0,  int8_t v1,  int8_t v2,  int8_t v3,  int8_t v4,  int8_t v5,  int8_t v6,  int8_t v7,
+      int8_t v8,  int8_t v9,  int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
+    ) {
+      return simd8<int8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  /**
-   * Get the raw JSON for this token.
-   *
-   * The string_view will always point into the input buffer.
-   *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
-   *
-   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view is guaranteed to be
-   * a non-space token.
-   *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
-   *
-   * See also value::raw_json().
-   */
-  simdjson_inline std::string_view raw_json_token() noexcept;
+    // Order-sensitive comparisons
+    simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return __lasx_xvmax_b(*this, other); }
+    simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return __lasx_xvmin_b(*this, other); }
+    simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return __lasx_xvslt_b(other, *this); }
+    simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return __lasx_xvslt_b(*this, other); }
+  };
 
-  /**
-   * Get a string_view pointing at this value in the JSON document.
-   * If this element is an array or an object, it consumes the array or the object
-   * and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
-   * If this element is a scalar (string, number, Boolean, null), it returns what
-   * raw_json_token() would return.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  // Unsigned bytes
+  template<>
+  struct simd8<uint8_t>: base8_numeric<uint8_t> {
+    simdjson_inline simd8() : base8_numeric<uint8_t>() {}
+    simdjson_inline simd8(const __m256i _value) : base8_numeric<uint8_t>(_value) {}
+    // Splat constructor
+    simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
+    // Array constructor
+    simdjson_inline simd8(const uint8_t values[32]) : simd8(load(values)) {}
+    // Member-by-member initialization
+    simdjson_inline simd8(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15,
+      uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
+      uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31
+    ) : simd8(__m256i(v32u8{
+      v0, v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10,v11,v12,v13,v14,v15,
+      v16,v17,v18,v19,v20,v21,v22,v23,
+      v24,v25,v26,v27,v28,v29,v30,v31
+    })) {}
+    // Repeat 16 values as many times as necessary (usually for lookup tables)
+    simdjson_inline static simd8<uint8_t> repeat_16(
+      uint8_t v0,  uint8_t v1,  uint8_t v2,  uint8_t v3,  uint8_t v4,  uint8_t v5,  uint8_t v6,  uint8_t v7,
+      uint8_t v8,  uint8_t v9,  uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
+    ) {
+      return simd8<uint8_t>(
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15,
+        v0, v1, v2, v3, v4, v5, v6, v7,
+        v8, v9, v10,v11,v12,v13,v14,v15
+      );
+    }
 
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+    // Saturated math
+    simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __lasx_xvsadd_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __lasx_xvssub_bu(*this, other); }
 
-  /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
-   */
-  simdjson_inline int32_t current_depth() const noexcept;
+    // Order-specific operations
+    simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return __lasx_xvmax_bu(*this, other); }
+    simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return __lasx_xvmin_bu(other, *this); }
+    // Same as >, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
+    // Same as <, but only guarantees true is nonzero (< guarantees true = -1)
+    simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
+    simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
+    simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
+    simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
 
-  /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed.
-   *
-   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
-   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
-   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
-   * or an object instance: there is no rewind and no invalidation.
-   *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
-   *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
-   *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
-   *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+    // Bit-specific operations
+    simdjson_inline simd8<bool> bits_not_set() const { return *this == uint8_t(0); }
+    simdjson_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
+    simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
+    simdjson_inline bool is_ascii() const {
+      __m256i mask = __lasx_xvmskltz_b(*this);
+      return (0 == __lasx_xvpickve2gr_w(mask, 0)) && (0 == __lasx_xvpickve2gr_w(mask, 4));
+    }
+    simdjson_inline bool bits_not_set_anywhere() const {
+      __m256i v = __lasx_xvmsknz_b(*this);
+      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
+    }
+    simdjson_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
+    simdjson_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const {
+      __m256i v = __lasx_xvmsknz_b(__lasx_xvand_v(*this, bits));
+      return (0 == __lasx_xvpickve2gr_w(v, 0)) && (0 == __lasx_xvpickve2gr_w(v, 4));
+    }
+    simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(__lasx_xvsrli_b(*this, N)); }
+    template<int N>
+    simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lasx_xvslli_b(*this, N)); }
+  };
 
-  /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
-   *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
+  template<typename T>
+  struct simd8x64 {
+    static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+    static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block.");
+    const simd8<T> chunks[NUM_CHUNKS];
 
+    simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
+    simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+    simd8x64() = delete; // no default constructor allowed
 
-protected:
-  /**
-   * Create a value.
-   */
-  simdjson_inline value(const value_iterator &iter) noexcept;
+    simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
+    simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+32)} {}
 
-  /**
-   * Skip this value, allowing iteration to continue.
-   */
-  simdjson_inline void skip() noexcept;
+    simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
+      uint32_t mask1 = uint32_t(mask);
+      uint32_t mask2 = uint32_t(mask >> 32);
+      __m256i zcnt = __lasx_xvpcnt_w(__m256i(v4u64{~mask, 0, 0, 0}));
+      uint64_t zcnt1 = __lasx_xvpickve2gr_wu(zcnt, 0);
+      uint64_t zcnt2 = __lasx_xvpickve2gr_wu(zcnt, 1);
+      // There should be a critical value which processes in scaler is faster.
+      if (zcnt1)
+        this->chunks[0].compress(mask1, output);
+      if (zcnt2)
+        this->chunks[1].compress(mask2, output + zcnt1);
+      return zcnt1 + zcnt2;
+    }
 
-  /**
-   * Start a value at the current position.
-   *
-   * (It should already be started; this is just a self-documentation method.)
-   */
-  static simdjson_inline value start(const value_iterator &iter) noexcept;
+    simdjson_inline void store(T ptr[64]) const {
+      this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
+      this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
+    }
 
-  /**
-   * Resume a value.
-   */
-  static simdjson_inline value resume(const value_iterator &iter) noexcept;
+    simdjson_inline uint64_t to_bitmask() const {
+      __m256i mask0 = __lasx_xvmskltz_b(this->chunks[0]);
+      __m256i mask1 = __lasx_xvmskltz_b(this->chunks[1]);
+      __m256i mask_tmp = __lasx_xvpickve_w(mask0, 4);
+      __m256i tmp = __lasx_xvpickve_w(mask1, 4);
+      mask0 = __lasx_xvinsve0_w(mask0, mask1, 1);
+      mask_tmp = __lasx_xvinsve0_w(mask_tmp, tmp, 1);
+      return __lasx_xvpickve2gr_du(__lasx_xvpackev_h(mask_tmp, mask0), 0);
+    }
 
-  /**
-   * Get the object, starting or resuming it as necessary
-   */
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+    simdjson_inline simd8<T> reduce_or() const {
+      return this->chunks[0] | this->chunks[1];
+    }
 
-  // simdjson_inline void log_value(const char *type) const noexcept;
-  // simdjson_inline void log_error(const char *message) const noexcept;
+    simdjson_inline uint64_t eq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] == mask,
+        this->chunks[1] == mask
+      ).to_bitmask();
+    }
 
-  value_iterator iter{};
+    simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
+      return  simd8x64<bool>(
+        this->chunks[0] == other.chunks[0],
+        this->chunks[1] == other.chunks[1]
+      ).to_bitmask();
+    }
 
-  friend class document;
-  friend class array_iterator;
-  friend class field;
-  friend class object;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<field>;
-  friend class field;
-};
+    simdjson_inline uint64_t lteq(const T m) const {
+      const simd8<T> mask = simd8<T>::splat(m);
+      return  simd8x64<bool>(
+        this->chunks[0] <= mask,
+        this->chunks[1] <= mask
+      ).to_bitmask();
+    }
+  }; // struct simd8x64<T>
 
-} // namespace ondemand
+} // namespace simd
+} // unnamed namespace
 } // namespace lasx
 } // namespace simdjson
 
+#endif // SIMDJSON_LASX_SIMD_H
+/* end file simdjson/lasx/simd.h */
+/* including simdjson/lasx/stringparsing_defs.h: #include "simdjson/lasx/stringparsing_defs.h" */
+/* begin file simdjson/lasx/stringparsing_defs.h */
+#ifndef SIMDJSON_LASX_STRINGPARSING_DEFS_H
+#define SIMDJSON_LASX_STRINGPARSING_DEFS_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/simd.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/lasx/bitmanipulation.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
 namespace simdjson {
+namespace lasx {
+namespace {
 
-template<>
-struct simdjson_result<lasx::ondemand::value> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value> {
+using namespace simd;
+
+// Holds backslashes and quotes locations.
+struct backslash_and_quote {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::value &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+  static constexpr uint32_t BYTES_PROCESSED = 32;
+  simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
 
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() noexcept;
+  simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
+  simdjson_inline bool has_backslash() { return bs_bits != 0; }
+  simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
+  simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
 
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  uint32_t bs_bits;
+  uint32_t quote_bits;
+}; // struct backslash_and_quote
 
-  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
+simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
+  // this can read up to 31 bytes beyond the buffer size, but we require
+  // SIMDJSON_PADDING of padding
+  static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
+  simd8<uint8_t> v(src);
+  v.store(dst);
+  return {
+      static_cast<uint32_t>((v == '\\').to_bitmask()),     // bs_bits
+      static_cast<uint32_t>((v == '"').to_bitmask()), // quote_bits
+  };
+}
 
-  template<typename T> simdjson_inline error_code get(T &out) noexcept;
+} // unnamed namespace
+} // namespace lasx
+} // namespace simdjson
 
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
+#endif // SIMDJSON_LASX_STRINGPARSING_DEFS_H
+/* end file simdjson/lasx/stringparsing_defs.h */
+
+#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
+/* end file simdjson/lasx/begin.h */
+/* including simdjson/generic/ondemand/amalgamated.h for lasx: #include "simdjson/generic/ondemand/amalgamated.h" */
+/* begin file simdjson/generic/ondemand/amalgamated.h for lasx */
+#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
+#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
 
-  /**
-   * Look up a field by name on an object (order-sensitive).
-   *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
-   *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
-   *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) noexcept;
+// Stuff other things depend on
+/* including simdjson/generic/ondemand/base.h for lasx: #include "simdjson/generic/ondemand/base.h" */
+/* begin file simdjson/generic/ondemand/base.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H
 
-  /**
-   * Look up a field by name on an object, without regard to key order.
-   *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
-   *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
-   *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field as not there when they are not in order).
-   *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) noexcept;
-  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) noexcept = delete;
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  /**
-   * Get the type of this JSON value.
-   *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
-   */
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+namespace simdjson {
+namespace lasx {
+/**
+ * A fast, simple, DOM-like interface that parses JSON as you use it.
+ *
+ * Designed for maximum speed and a lower memory profile.
+ */
+namespace ondemand {
 
-  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+/** Represents the depth of a JSON value (number of nested arrays/objects). */
+using depth_t = int32_t;
 
-  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-};
+/** @copydoc simdjson::lasx::number_type */
+using number_type = simdjson::lasx::number_type;
+
+/** @private Position in the JSON buffer indexes */
+using token_position = const uint32_t *;
+
+class array;
+class array_iterator;
+class document;
+class document_reference;
+class document_stream;
+class field;
+class json_iterator;
+enum class json_type;
+struct number;
+class object;
+class object_iterator;
+class parser;
+class raw_json_string;
+class token_iterator;
+class value;
+class value_iterator;
 
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
-/* end file simdjson/generic/ondemand/value.h for lasx */
-/* including simdjson/generic/ondemand/logger.h for lasx: #include "simdjson/generic/ondemand/logger.h" */
-/* begin file simdjson/generic/ondemand/logger.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H
+/* end file simdjson/generic/ondemand/base.h for lasx */
+/* including simdjson/generic/ondemand/deserialize.h for lasx: #include "simdjson/generic/ondemand/deserialize.h" */
+/* begin file simdjson/generic/ondemand/deserialize.h for lasx */
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
+#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <concepts>
 namespace simdjson {
-namespace lasx {
-namespace ondemand {
 
-// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
-// that the call to the log functions be side-effect free. Thus, for example, you should not
-// create temporary std::string instances.
-namespace logger {
+namespace tag_invoke_fn_ns {
+void tag_invoke();
+
+struct tag_invoke_fn {
+  template <typename Tag, typename... Args>
+    requires requires(Tag tag, Args &&...args) {
+      tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+    }
+  constexpr auto operator()(Tag tag, Args &&...args) const
+      noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
+                                   std::forward<Args>(args)...)))
+          -> decltype(tag_invoke(std::forward<Tag>(tag),
+                                 std::forward<Args>(args)...)) {
+    return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+  }
+};
+} // namespace tag_invoke_fn_ns
+
+inline namespace tag_invoke_ns {
+inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
+} // namespace tag_invoke_ns
+
+template <typename Tag, typename... Args>
+concept tag_invocable = requires(Tag tag, Args... args) {
+  tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
+};
+
+template <typename Tag, typename... Args>
+concept nothrow_tag_invocable =
+    tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
+      {
+        tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
+      } noexcept;
+    };
+
+template <typename Tag, typename... Args>
+using tag_invoke_result =
+    std::invoke_result<decltype(tag_invoke), Tag, Args...>;
+
+template <typename Tag, typename... Args>
+using tag_invoke_result_t =
+    std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
+
+template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
+
+
+struct deserialize_tag;
+
+/// These types are deserializable in a built-in way
+template <typename> struct is_builtin_deserializable : std::false_type {};
+template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
+template <> struct is_builtin_deserializable<double> : std::true_type {};
+template <> struct is_builtin_deserializable<bool> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::array> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::object> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::value> : std::true_type {};
+template <> struct is_builtin_deserializable<lasx::ondemand::raw_json_string> : std::true_type {};
+template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
+
+template <typename T>
+concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+template <typename T, typename ValT = lasx::ondemand::value>
+concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
+
+// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
+template <typename T, typename ValT = lasx::ondemand::value>
+concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
+
+/// Deserialize Tag
+inline constexpr struct deserialize_tag {
+  using value_type = lasx::ondemand::value;
+  using document_type = lasx::ondemand::document;
+  using document_reference_type = lasx::ondemand::document_reference;
 
-enum class log_level : int32_t {
-  info = 0,
-  error = 1
-};
+  // Customization Point for value
+  template <typename T>
+    requires custom_deserializable<T, value_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-#if SIMDJSON_VERBOSE_LOGGING
-  static constexpr const bool LOG_ENABLED = true;
-#else
-  static constexpr const bool LOG_ENABLED = false;
-#endif
+  // Customization Point for document
+  template <typename T>
+    requires custom_deserializable<T, document_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-// We do not want these functions to be 'really inlined' since real inlining is
-// for performance purposes and if you are using the loggers, you do not care about
-// performance (or should not).
-static inline void log_headers() noexcept;
-// If args are provided, title will be treated as format string
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-template <typename... Args>
-static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
-static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+  // Customization Point for document reference
+  template <typename T>
+    requires custom_deserializable<T, document_reference_type>
+  [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_reference_type>) {
+    return tag_invoke(*this, object, output);
+  }
 
-static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
-static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
 
-static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
-static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
-static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
-static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+} deserialize{};
 
-} // namespace logger
-} // namespace ondemand
-} // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
-/* end file simdjson/generic/ondemand/logger.h for lasx */
-/* including simdjson/generic/ondemand/token_iterator.h for lasx: #include "simdjson/generic/ondemand/token_iterator.h" */
-/* begin file simdjson/generic/ondemand/token_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+
+/* end file simdjson/generic/ondemand/deserialize.h for lasx */
+/* including simdjson/generic/ondemand/value_iterator.h for lasx: #include "simdjson/generic/ondemand/value_iterator.h" */
+/* begin file simdjson/generic/ondemand/value_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -119857,131 +112180,467 @@ namespace lasx {
 namespace ondemand {
 
 /**
- * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
- * detected by stage 1.
+ * Iterates through a single JSON value at a particular depth.
+ *
+ * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
+ * the caller to call the right ones.
  *
  * @private This is not intended for external use.
  */
-class token_iterator {
+class value_iterator {
+protected:
+  /** The underlying JSON iterator */
+  json_iterator *_json_iter{};
+  /** The depth of this value */
+  depth_t _depth{};
+  /**
+   * The starting token index for this value
+   */
+  token_position _start_position{};
+
 public:
+  simdjson_inline value_iterator() noexcept = default;
+
   /**
-   * Create a new invalid token_iterator.
+   * Denote that we're starting a document.
+   */
+  simdjson_inline void start_document() noexcept;
+
+  /**
+   * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * Optimized for scalars.
    */
-  simdjson_inline token_iterator() noexcept = default;
-  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
-  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
-  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
+  simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
 
   /**
-   * Advance to the next token (returning the current one).
+   * Tell whether the iterator is at the EOF mark
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  simdjson_inline bool at_end() const noexcept;
+
   /**
-   * Reports the current offset in bytes from the start of the underlying buffer.
+   * Tell whether the iterator is at the start of the value
    */
-  simdjson_inline uint32_t current_offset() const noexcept;
+  simdjson_inline bool at_start() const noexcept;
+
   /**
-   * Get the JSON text for a given token (relative).
+   * Tell whether the value is open--if the value has not been used, or the array/object is still open.
+   */
+  simdjson_inline bool is_open() const noexcept;
+
+  /**
+   * Tell whether the value is at an object's first field (just after the {).
+   */
+  simdjson_inline bool at_first_field() const noexcept;
+
+  /**
+   * Abandon all iteration.
+   */
+  simdjson_inline void abandon() noexcept;
+
+  /**
+   * Get the child value as a value_iterator.
+   */
+  simdjson_inline value_iterator child_value() const noexcept;
+
+  /**
+   * Get the depth of this value.
+   */
+  simdjson_inline int32_t depth() const noexcept;
+
+  /**
+   * Get the JSON type of this value.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() const noexcept;
+
+  /**
+   * @addtogroup object Object iteration
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * Methods to iterate and find object fields. These methods generally *assume* the value is
+   * actually an object; the caller is responsible for keeping track of that fact.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used...
+   * @{
    */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * Start an object iteration.
    *
-   * The length will include any whitespace at the end of the token.
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
+  /**
+   * Start an object iteration from the root.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
+  /**
+   * Checks whether an object could be started from the root. May be called by start_root_object.
+   *
+   * @returns SUCCESS if it is possible to safely start an object from the root (document level).
+   * @error INCORRECT_TYPE if there is no opening {
+   * @error TAPE_ERROR if there is no matching } at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
+  /**
+   * Start an object iteration after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
+  /**
+   * Start an object iteration from the root, after the user has already checked and moved past the {.
+   *
+   * Does not move the iterator unless the object is empty ({}).
+   *
+   * @returns Whether the object had any fields (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
 
   /**
-   * Get the JSON text for a given token.
+   * Moves to the next field in an object.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Looks for , and }. If } is found, the object is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
    *
-   * @param position The position of the token.
+   * @return whether there is another field in the object.
+   * @error TAPE_ERROR If there is a comma missing between fields.
+   * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
+
+  /**
+   * Get the current field's key.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
+
+  /**
+   * Pass the : in the field and move to its value.
+   */
+  simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
+
+  /**
+   * Find the next field with the given key.
+   *
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
    *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a given token.
+   * Find the next field with the given key, *without* unescaping. This assumes object order: it
+   * will not find the field if it was already passed when looking for some *other* field.
    *
-   * The length will include any whitespace at the end of the token.
+   * Assumes you have called next_field() or otherwise matched the previous value.
    *
-   * @param position The position of the token.
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
+
   /**
-   * Get the maximum length of the JSON text for a root token.
+   * Find the field with the given key without regard to order, and *without* unescaping.
    *
-   * The length will include any whitespace at the end of the token.
+   * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
    *
-   * @param position The position of the token (start of the document).
+   * Assumes you have called next_field() or otherwise matched the previous value.
+   *
+   * This means the iterator must be sitting at the next key:
+   *
+   * ```
+   * { "a": 1, "b": 2 }
+   *           ^
+   * ```
+   *
+   * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
+   * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
+   * fail to match some keys with escapes (\u, \n, etc.).
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
+
+  /** @} */
+
   /**
-   * Return the current index.
+   * @addtogroup array Array iteration
+   * Methods to iterate over array elements. These methods generally *assume* the value is actually
+   * an object; the caller is responsible for keeping track of that fact.
+   * @{
    */
-  simdjson_inline token_position position() const noexcept;
+
   /**
-   * Reset to a previously saved index.
+   * Check for an opening [ and start an array iteration.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
    */
-  simdjson_inline void set_position(token_position target_position) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
+  /**
+   * Check for an opening [ and start an array iteration while at the root.
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
+  /**
+   * Checks whether an array could be started from the root. May be called by start_root_array.
+   *
+   * @returns SUCCESS if it is possible to safely start an array from the root (document level).
+   * @error INCORRECT_TYPE If there is no [.
+   * @error TAPE_ERROR if there is no matching ] at end of document
+   */
+  simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
+  /**
+   * Start an array iteration, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
+  /**
+   * Start an array iteration from the root, after the user has already checked and moved past the [.
+   *
+   * Does not move the iterator unless the array is empty ([]).
+   *
+   * @returns Whether the array had any elements (returns false for empty).
+   * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
+   *        array or object is incomplete).
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
 
-  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
-  // different calls to advance the iterator based on *their own* state.
+  /**
+   * Moves to the next element in an array.
+   *
+   * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
+   * Otherwise, it advances to the next value.
+   *
+   * @return Whether there is another element in the array.
+   * @error TAPE_ERROR If there is a comma missing between elements.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
 
-  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
-  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+  /**
+   * Get a child value iterator.
+   */
+  simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
+
+  /** @} */
+
+  /**
+   * @defgroup scalar Scalar values
+   * @addtogroup scalar
+   * @{
+   */
+
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
+  simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
+  template <typename string_type>
+  simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
+
+  simdjson_inline error_code error() const noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline const json_iterator &json_iter() const noexcept;
+  simdjson_inline json_iterator &json_iter() noexcept;
+
+  simdjson_inline void assert_is_valid() const noexcept;
+  simdjson_inline bool is_valid() const noexcept;
 
+  /** @} */
 protected:
-  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
+  /**
+   * Restarts an array iteration.
+   * @returns Whether the array has any elements (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_array() noexcept;
+  /**
+   * Restarts an object iteration.
+   * @returns Whether the object has any fields (returns false for empty).
+   */
+  simdjson_inline simdjson_result<bool> reset_object() noexcept;
+  /**
+   * move_at_start(): moves us so that we are pointing at the beginning of
+   * the container. It updates the index so that at_start() is true and it
+   * syncs the depth. The user can then create a new container instance.
+   *
+   * Usage: used with value::count_elements().
+   **/
+  simdjson_inline void move_at_start() noexcept;
 
   /**
-   * Get the index of the JSON text for a given token (relative).
+   * move_at_container_start(): moves us so that we are pointing at the beginning of
+   * the container so that assert_at_container_start() passes.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Usage: used with reset_array() and reset_object().
+   **/
+   simdjson_inline void move_at_container_start() noexcept;
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
+  simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
+
+  simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
+  simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
+  simdjson_inline const uint8_t *peek_start() const noexcept;
+  simdjson_inline uint32_t peek_start_length() const noexcept;
+  simdjson_inline uint32_t peek_root_length() const noexcept;
+
+  /**
+   * The general idea of the advance_... methods and the peek_* methods
+   * is that you first peek and check that you have desired type. If you do,
+   * and only if you do, then you advance.
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
-   *              1 = next token, -1 = prev token.
+   * We used to unconditionally advance. But this made reasoning about our
+   * current state difficult.
+   * Suppose you always advance. Look at the 'value' matching the key
+   * "shadowable" in the following example...
+   *
+   * ({"globals":{"a":{"shadowable":[}}}})
+   *
+   * If the user thinks it is a Boolean and asks for it, then we check the '[',
+   * decide it is not a Boolean, but still move into the next character ('}'). Now
+   * we are left pointing at '}' right after a '['. And we have not yet reported
+   * an error, only that we do not have a Boolean.
+   *
+   * If, instead, you just stand your ground until it is content that you know, then
+   * you will only even move beyond the '[' if the user tells you that you have an
+   * array. So you will be at the '}' character inside the array and, hopefully, you
+   * will then catch the error because an array cannot start with '}', but the code
+   * processing Boolean values does not know this.
+   *
+   * So the contract is: first call 'peek_...' and then call 'advance_...' only
+   * if you have determined that it is a type you can handle.
+   *
+   * Unfortunately, it makes the code more verbose, longer and maybe more error prone.
    */
-  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+
+  simdjson_inline void advance_scalar(const char *type) noexcept;
+  simdjson_inline void advance_root_scalar(const char *type) noexcept;
+  simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
+
+  simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
+  simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
+
+
+  simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
+  simdjson_inline error_code end_container() noexcept;
+
   /**
-   * Get the index of the JSON text for a given token.
+   * Advance to a place expecting a value (increasing depth).
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * @return The current token (the one left behind).
+   * @error TAPE_ERROR If the document ended early.
+   */
+  simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
+
+  simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
+  simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
+
+  simdjson_inline bool is_at_start() const noexcept;
+  /**
+   * is_at_iterator_start() returns true on an array or object after it has just been
+   * created, whether the instance is empty or not.
    *
-   * @param position The position of the token.
+   * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
+   */
+  simdjson_inline bool is_at_iterator_start() const noexcept;
+
+  /**
+   * Assuming that we are within an object, this returns true if we
+   * are pointing at a key.
    *
+   * Usage: the skip_child() method should never be used while we are pointing
+   * at a key inside an object.
    */
-  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
+  simdjson_inline bool is_at_key() const noexcept;
 
-  const uint8_t *buf{};
-  token_position _position{};
+  inline void assert_at_start() const noexcept;
+  inline void assert_at_container_start() const noexcept;
+  inline void assert_at_root() const noexcept;
+  inline void assert_at_child() const noexcept;
+  inline void assert_at_next() const noexcept;
+  inline void assert_at_non_root_start() const noexcept;
 
-  friend class json_iterator;
-  friend class value_iterator;
+  /** Get the starting position of this value */
+  simdjson_inline token_position start_position() const noexcept;
+
+  /** @copydoc error_code json_iterator::position() const noexcept; */
+  simdjson_inline token_position position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position last_position() const noexcept;
+  /** @copydoc error_code json_iterator::end_position() const noexcept; */
+  simdjson_inline token_position end_position() const noexcept;
+  /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+
+  friend class document;
   friend class object;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-};
+  friend class array;
+  friend class value;
+  friend class field;
+}; // value_iterator
 
 } // namespace ondemand
 } // namespace lasx
@@ -119990,707 +112649,711 @@ class token_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::token_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::token_iterator> {
+struct simdjson_result<lasx::ondemand::value_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::token_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::value_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
-/* end file simdjson/generic/ondemand/token_iterator.h for lasx */
-/* including simdjson/generic/ondemand/json_iterator.h for lasx: #include "simdjson/generic/ondemand/json_iterator.h" */
-/* begin file simdjson/generic/ondemand/json_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H
+/* end file simdjson/generic/ondemand/value_iterator.h for lasx */
+/* including simdjson/generic/ondemand/value.h for lasx: #include "simdjson/generic/ondemand/value.h" */
+/* begin file simdjson/generic/ondemand/value.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+#include <type_traits>
+
 namespace simdjson {
+
 namespace lasx {
 namespace ondemand {
-
 /**
- * Iterates through JSON tokens, keeping track of depth and string buffer.
- *
- * @private This is not intended for external use.
+ * An ephemeral JSON value returned during iteration. It is only valid for as long as you do
+ * not access more data in the JSON document.
  */
-class json_iterator {
-protected:
-  token_iterator token{};
-  ondemand::parser *parser{};
+class value {
+public:
   /**
-   * Next free location in the string buffer.
+   * Create a new invalid value.
    *
-   * Used by raw_json_string::unescape() to have a place to unescape strings to.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  uint8_t *_string_buf_loc{};
+  simdjson_inline value() noexcept = default;
+
   /**
-   * JSON error, if there is one.
+   * Get this value as the given type.
    *
-   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
    *
-   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
-   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
-   * this is not elided, we should make sure it's at least not using up a register. Failing that,
-   * we should store it in document so there's only one of them.
-   */
-  error_code error{SUCCESS};
-  /**
-   * Depth of the current token in the JSON.
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
    *
-   * - 0 = finished with document
-   * - 1 = document root value (could be [ or {, not yet known)
-   * - 2 = , or } inside root array/object
-   * - 3 = key or value inside root array/object.
-   */
-  depth_t _depth{};
-  /**
-   * Beginning of the document indexes.
-   * Normally we have root == parser->implementation->structural_indexes.get()
-   * but this may differ, especially in streaming mode (where we have several
-   * documents);
-   */
-  token_position _root{};
-  /**
-   * Normally, a json_iterator operates over a single document, but in
-   * some cases, we may have a stream of documents. This attribute is meant
-   * as meta-data: the json_iterator works the same irrespective of the
-   * value of this attribute.
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
    */
-  bool _streaming{false};
+  template <typename T>
+  simdjson_inline simdjson_result<T> get()
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
 
-public:
-  simdjson_inline json_iterator() noexcept = default;
-  simdjson_inline json_iterator(json_iterator &&other) noexcept;
-  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
-  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
-  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
-  /**
-   * Skips a JSON value, whether it is a scalar, array or object.
-   */
-  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
 
   /**
-   * Tell whether the iterator is still at the start
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline bool at_root() const noexcept;
+  template <typename T>
+  simdjson_inline error_code get(T &out)
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
+#else
+    noexcept
+#endif
+ {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, value>) {
+      return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
 
   /**
-   * Tell whether we should be expected to run in streaming
-   * mode (iterating over many documents). It is pure metadata
-   * that does not affect how the iterator works. It is used by
-   * start_root_array() and start_root_object().
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline bool streaming() const noexcept;
+  simdjson_inline simdjson_result<array> get_array() noexcept;
 
   /**
-   * Get the root value iterator
-   */
-  simdjson_inline token_position root_position() const noexcept;
-  /**
-   * Assert that we are at the document depth (== 1)
-   */
-  simdjson_inline void assert_at_document_depth() const noexcept;
-  /**
-   * Assert that we are at the root of the document
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  simdjson_inline void assert_at_root() const noexcept;
+  simdjson_inline simdjson_result<object> get_object() noexcept;
 
   /**
-   * Tell whether the iterator is at the EOF mark
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
 
   /**
-   * Tell whether the iterator is live (has not been moved).
+   * Cast this JSON value (inside string) to a unsigned integer.
+   *
+   * @returns A unsigned 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool is_alive() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
 
   /**
-   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline void abandon() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
 
   /**
-   * Advance the current token without modifying depth.
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
 
   /**
-   * Returns true if there is a single token in the index (i.e., it is
-   * a JSON with a scalar value such as a single number).
+   * Cast this JSON value to a double.
    *
-   * @return whether there is a single token
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline bool is_single_token() const noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
   /**
-   * Assert that there are at least the given number of tokens left.
+   * Cast this JSON value (inside string) to a double
    *
-   * Has no effect in release builds.
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+
   /**
-   * Assert that the given position addresses an actual token (is within bounds).
+   * Cast this JSON value to a string.
    *
-   * Has no effect in release builds.
-   */
-  simdjson_inline void assert_valid_position(token_position position) const noexcept;
-  /**
-   * Get the JSON text for a given token (relative).
+   * The string is guaranteed to be valid UTF-8.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Equivalent to get<std::string_view>().
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
-   */
-  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current token (or relative).
+   * In some instances, you may want to allow replacement of invalid Unicode sequences.
+   * You may do so by passing the allow_replacement parameter as true. In the following
+   * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
+   * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
+   * replacement character (U+FFFD).
    *
-   * The length will include any whitespace at the end of the token.
+   *   simdjson::ondemand::parser parser;
+   *   auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
+   *   simdjson::ondemand::document doc = parser.iterate(json);
+   *   auto view = doc["deviceId"].get_string(true);
    *
-   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+
   /**
-   * Get a pointer to the current location in the input buffer.
-   *
-   * This is not null-terminated; it is a view into the JSON.
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
    *
-   * You may be pointing outside of the input buffer: it is not generally
-   * safe to dereference this pointer.
-   */
-  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
-  /**
-   * Get the JSON text for a given token.
+   * The string is guaranteed to be valid UTF-8.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
    *
-   * @param position The position of the token to retrieve.
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
    */
-  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+
   /**
-   * Get the maximum length of the JSON text for the current token (or relative).
-   *
-   * The length will include any whitespace at the end of the token.
+   * Cast this JSON value to a "wobbly" string.
    *
-   * @param position The position of the token to retrieve.
-   */
-  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
-  /**
-   * Get the maximum length of the JSON text for the current root token.
+   * The string is may not be a valid UTF-8 string.
+   * See https://simonsapin.github.io/wtf-8/
    *
-   * The length will include any whitespace at the end of the token.
+   * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
+   * is an error.
    *
-   * @param position The position of the token to retrieve.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
   /**
-   * Get the JSON text for the last token in the document.
+   * Cast this JSON value to a raw_json_string.
    *
-   * This is not null-terminated; it is a view into the JSON.
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
    *
-   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
-   * it is not used ...
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
    */
-  simdjson_inline const uint8_t *peek_last() const noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
 
   /**
-   * Ascend one level.
-   *
-   * Validates that the depth - 1 == parent_depth.
+   * Cast this JSON value to a bool.
    *
-   * @param parent_depth the expected parent depth.
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
    */
-  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
 
   /**
-   * Descend one level.
-   *
-   * Validates that the new depth == child_depth.
+   * Checks if this JSON value is null. If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
    *
-   * @param child_depth the expected child depth.
-   */
-  simdjson_inline void descend_to(depth_t child_depth) noexcept;
-  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
-
-  /**
-   * Get current depth.
-   */
-  simdjson_inline depth_t depth() const noexcept;
-
-  /**
-   * Get current (writeable) location in the string buffer.
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
    */
-  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
+#if SIMDJSON_EXCEPTIONS
   /**
-   * Report an unrecoverable error, preventing further iteration.
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.).
    *
-   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
-
-  /**
-   * Log error, but don't stop iteration.
-   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
-   * @param message An error message to report with the error.
-   */
-  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
-
-  /**
-   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
-   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
-   * The buffer (tmpbuf) is padded with space characters.
-   */
-  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
-
-  simdjson_inline token_position position() const noexcept;
-  /**
-   * Write the raw_json_string to the string buffer and return a string_view.
-   * Each raw_json_string should be unescaped once, or else the string buffer might
-   * overflow.
-   */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
-
-  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
-
-  simdjson_inline error_code consume_character(char c) noexcept;
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  simdjson_inline token_position start_position(depth_t depth) const noexcept;
-  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
-#endif
-
-  /* Useful for debugging and logging purposes. */
-  inline std::string to_string() const noexcept;
-
-  /**
-   * Returns the current location in the document if in bounds.
-   */
-  inline simdjson_result<const char *> current_location() const noexcept;
-
-  /**
-   * Updates this json iterator so that it is back at the beginning of the document,
-   * as if it had just been created.
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
    */
-  inline void rewind() noexcept;
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
   /**
-   * This checks whether the {,},[,] are balanced so that the document
-   * ends with proper zero depth. This requires scanning the whole document
-   * and it may be expensive. It is expected that it will be rarely called.
-   * It does not attempt to match { with } and [ with ].
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
    */
-  inline bool balanced() const noexcept;
-protected:
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /// The last token before the end
-  simdjson_inline token_position last_position() const noexcept;
-  /// The token *at* the end. This points at gibberish and should only be used for comparison.
-  simdjson_inline token_position end_position() const noexcept;
-  /// The end of the buffer.
-  simdjson_inline token_position end() const noexcept;
-
-  friend class document;
-  friend class document_stream;
-  friend class object;
-  friend class array;
-  friend class value;
-  friend class raw_json_string;
-  friend class parser;
-  friend class value_iterator;
-  friend class field;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
-  template <typename... Args>
-  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
-}; // json_iterator
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::json_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_iterator> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::json_iterator &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-
-  simdjson_inline simdjson_result() noexcept = default;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
-/* end file simdjson/generic/ondemand/json_iterator.h for lasx */
-/* including simdjson/generic/ondemand/json_type.h for lasx: #include "simdjson/generic/ondemand/json_type.h" */
-/* begin file simdjson/generic/ondemand/json_type.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
-
-/**
- * The type of a JSON value.
- */
-enum class json_type {
-    // Start at 1 to catch uninitialized / default values more easily
-    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
-    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
-    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
-    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
-    boolean, ///< A JSON boolean (true or false)
-    null     ///< A JSON null    (null)
-};
-
-/**
- * A type representing a JSON number.
- * The design of the struct is deliberately straight-forward. All
- * functions return standard values with no error check.
- */
-struct number {
-
-  /**
-   * return the automatically determined type of
-   * the number: number_type::floating_point_number,
-   * number_type::signed_integer or number_type::unsigned_integer.
+  simdjson_inline operator array() noexcept(false);
+  /**
+   * Cast this JSON value to an object.
    *
-   *    enum class number_type {
-   *        floating_point_number=1, /// a binary64 number
-   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
-   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
-   *    };
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
    */
-  simdjson_inline ondemand::number_type get_number_type() const noexcept;
+  simdjson_inline operator object() noexcept(false);
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::unsigned_integer.
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline bool is_uint64() const noexcept;
+  simdjson_inline operator uint64_t() noexcept(false);
   /**
-   * return the value as a uint64_t, only valid if is_uint64() is true.
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline uint64_t get_uint64() const noexcept;
-  simdjson_inline operator uint64_t() const noexcept;
-
+  simdjson_inline operator int64_t() noexcept(false);
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::signed_integer.
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline bool is_int64() const noexcept;
+  simdjson_inline operator double() noexcept(false);
   /**
-   * return the value as a int64_t, only valid if is_int64() is true.
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Equivalent to get<std::string_view>().
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_inline int64_t get_int64() const noexcept;
-  simdjson_inline operator int64_t() const noexcept;
-
-
+  simdjson_inline operator std::string_view() noexcept(false);
   /**
-   * return true if the automatically determined type of
-   * the number is number_type::floating_point_number.
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
    */
-  simdjson_inline bool is_double() const noexcept;
+  simdjson_inline operator raw_json_string() noexcept(false);
   /**
-   * return the value as a double, only valid if is_double() is true.
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
    */
-  simdjson_inline double get_double() const noexcept;
-  simdjson_inline operator double() const noexcept;
+  simdjson_inline operator bool() noexcept(false);
+#endif
 
   /**
-   * Convert the number to a double. Though it always succeed, the conversion
-   * may be lossy if the number cannot be represented exactly.
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   *
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline double as_double() const noexcept;
-
-
-protected:
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
   /**
-   * The next block of declaration is designed so that we can call the number parsing
-   * functions on a number type. They are protected and should never be used outside
-   * of the core simdjson library.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  friend class value_iterator;
-  template<typename W>
-  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
-  template<typename W>
-  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
-  /** Store a signed 64-bit value to the number. */
-  simdjson_inline void append_s64(int64_t value) noexcept;
-  /** Store an unsigned 64-bit value to the number. */
-  simdjson_inline void append_u64(uint64_t value) noexcept;
-  /** Store a double value to the number. */
-  simdjson_inline void append_double(double value) noexcept;
-  /** Specifies that the value is a double, but leave it undefined. */
-  simdjson_inline void skip_double() noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
   /**
-   * End of friend declarations.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * Performance hint: You should only call count_elements() as a last
+   * resort as it may require scanning the document twice or more.
    */
-
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Our attributes are a union type (size = 64 bits)
-   * followed by a type indicator.
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method on the object instance.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
    */
-  union {
-    double floating_point_number;
-    int64_t signed_integer;
-    uint64_t unsigned_integer;
-  } payload{0};
-  number_type type{number_type::signed_integer};
-};
-
-/**
- * Write the JSON type to the output stream
- *
- * @param out The output stream.
- * @param type The json_type.
- */
-inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
-
-#if SIMDJSON_EXCEPTIONS
-/**
- * Send JSON type to an output stream.
- *
- * @param out The output stream.
- * @param type The json_type.
- * @throw simdjson_error if the result being printed has an error. If there is an error with the
- *        underlying output stream, that error will be propagated (simdjson_error will not be
- *        thrown).
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
-#endif
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::json_type> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_type> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::json_type &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-};
-
-} // namespace simdjson
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   *
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   */
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
-/* end file simdjson/generic/ondemand/json_type.h for lasx */
-/* including simdjson/generic/ondemand/raw_json_string.h for lasx: #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* begin file simdjson/generic/ondemand/raw_json_string.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
+  simdjson_result<value> operator[](int) noexcept = delete;
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  /**
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @return The type of JSON value (json_type::array, json_type::object, json_type::string,
+   *     json_type::number, json_type::boolean, or json_type::null).
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
 
-/**
- * A string escaped per JSON rules, terminated with quote ("). They are used to represent
- * unescaped keys inside JSON documents.
- *
- * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
- * JSON file.)
- *
- * This class is deliberately simplistic and has little functionality. You can
- * compare a raw_json_string instance with an unescaped C string, but
- * that is nearly all you can do.
- *
- * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
- * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
- * instance. Doing so requires you to have a sufficiently large buffer.
- *
- * The raw_json_string instances originate typically from field instance which in turn represent
- * key-value pairs from object instances. From a field instance, you get the raw_json_string
- * instance by calling key(). You can, if you want a more usable string_view instance, call
- * the unescaped_key() method on the field instance. You may also create a raw_json_string from
- * any other string value, with the value.get_raw_json_string() method. Again, you can get
- * a more usable string_view instance by calling get_string().
- *
- */
-class raw_json_string {
-public:
   /**
-   * Create a new invalid raw_json_string.
+   * Checks whether the value is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
    */
-  simdjson_inline raw_json_string() noexcept = default;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  /**
+   * Checks whether the value is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
   /**
-   * Create a new invalid raw_json_string pointed at the given location in the JSON.
+   * Checks whether the value is a negative number.
    *
-   * The given location must be just *after* the beginning quote (") in the JSON file.
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the value is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
    *
-   * It *must* be terminated by a ", and be a valid JSON string.
+   * Performance note: if you call this function systematically
+   * before parsing a number, you may have fallen for a performance
+   * anti-pattern.
+   *
+   * @returns true if the number if negative.
    */
-  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
   /**
-   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
    *
-   * It is possible for this function to return a null pointer if the instance
-   * has outlived its existence.
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808.
+   * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits,
+   * in which case the digit_count is set to the length of the big integer string.
+   * Otherwise, get_number_type() has value number_type::floating_point_number.
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
    */
-  simdjson_inline const char * raw() const noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
-   * and if the raw_json_string instance has a quote character at byte index target.size().
-   * We never read more than length + 1 bytes in the raw_json_string instance.
-   * If length is smaller than target.size(), this will return false.
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
    *
-   * The std::string_view instance may contain any characters. However, the caller
-   * is responsible for setting length so that length bytes may be read in the
-   * raw_json_string.
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
    *
-   * Performance: the comparison may be done using memcmp which may be efficient
-   * for long strings.
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   *
+   * Performance note: this is designed with performance in mind. When
+   * calling 'get_number()', you scan the number string only once, determining
+   * efficiently the type and storing it in an efficient manner.
    */
-  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The std::string_view instance should not contain unescaped quote characters:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Get the raw JSON for this token.
    *
-   * Performance: the comparison is done byte-by-byte which might be inefficient for
-   * long strings.
+   * The string_view will always point into the input buffer.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   * The string_view is *not* null-terminated. However, if this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view is guaranteed to be
+   * a non-space token.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   *
+   * See also value::raw_json().
    */
-  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+  simdjson_inline std::string_view raw_json_token() noexcept;
 
   /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   * The provided C string should not contain an unescaped quote character:
-   * the caller is responsible for this check. See is_free_from_unescaped_quote.
+   * Get a string_view pointing at this value in the JSON document.
+   * If this element is an array or an object, it consumes the array or the object
+   * and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
+   * If this element is a scalar (string, number, Boolean, null), it returns what
+   * raw_json_token() would return.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
    *
-   * If target is a compile-time constant, and your compiler likes you,
-   * you should be able to do the following without performance penalty...
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
+
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
-   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
-   *   s.unsafe_is_equal(target);
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed.
+   *
+   * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
+   * standardized (by RFC 6901). We provide some experimental support for JSON pointers
+   * on non-document instances.  Yet it is not the case when calling at_pointer on an array
+   * or an object instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
-   * This compares the current instance to the std::string_view target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
 
-  /**
-   * This compares the current instance to the C string target: returns true if
-   * they are byte-by-byte equal (no escaping is done).
-   */
-  simdjson_inline bool is_equal(const char* target) const noexcept;
 
+protected:
   /**
-   * Returns true if target is free from unescaped quote. If target is known at
-   * compile-time, we might expect the computation to happen at compile time with
-   * many compilers (not all!).
+   * Create a value.
    */
-  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
-  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
-
-private:
-
+  simdjson_inline value(const value_iterator &iter) noexcept;
 
   /**
-   * This will set the inner pointer to zero, effectively making
-   * this instance unusable.
+   * Skip this value, allowing iteration to continue.
    */
-  simdjson_inline void consume() noexcept { buf = nullptr; }
+  simdjson_inline void skip() noexcept;
 
   /**
-   * Checks whether the inner pointer is non-null and thus usable.
+   * Start a value at the current position.
+   *
+   * (It should already be started; this is just a self-documentation method.)
    */
-  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+  static simdjson_inline value start(const value_iterator &iter) noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result will be a valid UTF-8.
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
-   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
+   * Resume a value.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+  static simdjson_inline value resume(const value_iterator &iter) noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
-   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
-   *
-   * ## IMPORTANT: string_view lifetime
-   *
-   * The string_view is only valid until the next parse() call on the parser.
-   *
-   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * Get the object, starting or resuming it as necessary
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
-  const uint8_t * buf{};
-  friend class object;
-  friend class field;
-  friend class parser;
-  friend struct simdjson_result<raw_json_string>;
-};
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
 
-simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+  // simdjson_inline void log_value(const char *type) const noexcept;
+  // simdjson_inline void log_error(const char *message) const noexcept;
 
-/**
- * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
- * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
- */
-simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
-simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
-simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+  value_iterator iter{};
 
+  friend class document;
+  friend class array_iterator;
+  friend class field;
+  friend class object;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<field>;
+  friend class field;
+};
 
 } // namespace ondemand
 } // namespace lasx
@@ -120699,397 +113362,335 @@ simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_js
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::raw_json_string> : public lasx::implementation_simdjson_result_base<lasx::ondemand::raw_json_string> {
+struct simdjson_result<lasx::ondemand::value> : public lasx::implementation_simdjson_result_base<lasx::ondemand::value> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::value &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
-
-  simdjson_inline simdjson_result<const char *> raw() const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept;
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
-/* end file simdjson/generic/ondemand/raw_json_string.h for lasx */
-/* including simdjson/generic/ondemand/parser.h for lasx: #include "simdjson/generic/ondemand/parser.h" */
-/* begin file simdjson/generic/ondemand/parser.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
-
-#include <memory>
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() noexcept;
 
-/**
- * The default batch size for document_stream instances for this On-Demand kernel.
- * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
- * in the future.
- */
-static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
-/**
- * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
- * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
- * most users will want a much larger batch size.
- *
- * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
- * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
- */
-static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-/**
- * A JSON fragment iterator.
- *
- * This holds the actual iterator as well as the buffer for writing strings.
- */
-class parser {
-public:
-  /**
-   * Create a JSON parser.
-   *
-   * The new parser will have zero capacity.
-   */
-  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
 
-  inline parser(parser &&other) noexcept = default;
-  simdjson_inline parser(const parser &other) = delete;
-  simdjson_inline parser &operator=(const parser &other) = delete;
-  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+  template<typename T> simdjson_inline error_code get(T &out) noexcept;
 
-  /** Deallocate the JSON parser. */
-  inline ~parser() noexcept = default;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
 
   /**
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   document doc = parser.iterate(json);
-   *
-   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
-   * Otherwise the iterate method may return an error. In particular, the whole input should be
-   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
-   * document. If there is a UTF-8 BOM, the parser skips it.
-   *
-   * ### IMPORTANT: Validate what you use
-   *
-   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
-   * iterate does not parse and validate the whole document.
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
-   *
-   * ### IMPORTANT: Document Lifetime
-   *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * ### std::string references
-   *
-   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
-   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
+   * Look up a field by name on an object (order-sensitive).
    *
-   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
-   * the string but before the end of the allocated memory (std::string::capacity()).
-   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
-   * container-overflow checks, you may encounter sanitizer warnings.
-   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
-   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
-   * which can be be passed to the parser's iterate function:
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
    *
-   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
-   *    document doc = parser.iterate(simdjson::pad(json));
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
    *
-   * @param json The JSON to parse.
-   * @param len The length of the JSON.
-   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
-   * @return The document, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
-  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
-  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) noexcept;
 
   /**
-   * @private
-   *
-   * Start iterating an on-demand JSON document.
-   *
-   *   ondemand::parser parser;
-   *   json_iterator doc = parser.iterate(json);
-   *
-   * ### IMPORTANT: Buffer Lifetime
-   *
-   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
-   * long as the document iteration.
-   *
-   * ### IMPORTANT: Document Lifetime
-   *
-   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
-   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
-   * you call parse() again or destroy the parser.
-   *
-   * The ondemand::document instance holds the iterator. The document must remain in scope
-   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   * Look up a field by name on an object, without regard to key order.
    *
-   * ### REQUIRED: Buffer Padding
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
    *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
    *
-   * @param json The JSON to parse.
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field as not there when they are not in order).
    *
-   * @return The iterator, or an error:
-   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
-   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
-   *           allocation fails.
-   *         - EMPTY if the document is all whitespace.
-   *         - UTF8_ERROR if the document is not valid UTF-8.
-   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
-   *         - UNCLOSED_STRING if there is an unclosed string in the document.
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
-  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
-
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) noexcept;
+  /** @overload simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) noexcept = delete;
 
   /**
-   * Parse a buffer containing many JSON documents.
-   *
-   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
-   *   ondemand::parser parser;
-   *   ondemand::document_stream docs = parser.iterate_many(json);
-   *   for (auto & doc : docs) {
-   *     std::cout << doc["foo"] << std::endl;
-   *   }
-   *   // Prints 1 2 3
-   *
-   * No copy of the input buffer is made.
-   *
-   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
-   *
-   * The caller is responsabile to ensure that the input string data remains unchanged and is
-   * not deleted during the loop.
-   *
-   * ### Format
-   *
-   * The buffer must contain a series of one or more JSON documents, concatenated into a single
-   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
-   * then starts parsing the next document at that point. (It does this with more parallelism and
-   * lookahead than you might think, though.)
-   *
-   * documents that consist of an object or array may omit the whitespace between them, concatenating
-   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
-   * arrays or objects) MUST be separated with ASCII whitespace.
-   *
-   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
-   * If there is a UTF-8 BOM, the parser skips it.
-   *
-   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
-   * Setting batch_size to excessively large or excessively small values may impact negatively the
-   * performance.
-   *
-   * ### REQUIRED: Buffer Padding
-   *
-   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
-   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
-   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
-   * SIMDJSON_PADDING bytes to avoid runtime warnings.
-   *
-   * ### Threads
-   *
-   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
-   * hood to do some lookahead.
-   *
-   * ### Parser Capacity
-   *
-   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
-   * to handle it (up to max_capacity).
+   * Get the type of this JSON value.
    *
-   * @param buf The concatenated JSON to parse.
-   * @param len The length of the concatenated JSON.
-   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
-   *                   spot is cache-related: small enough to fit in cache, yet big enough to
-   *                   parse as many documents as possible in one tight loop.
-   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
-   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
-   *                   separated by commas instead of whitespace. It comes with a performance
-   *                   penalty because the entire document is indexed at once (and the document must be
-   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
-   *                   is effectively ignored, as it is set to at least the document size.
-   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
-   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
-   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
-   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
-   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
    */
-  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
-  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
-  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
-  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
 
-  /** @private We do not want to allow implicit conversion from C string to std::string. */
-  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+  /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-  /** The capacity of this parser (the largest document it can process). */
-  simdjson_pure simdjson_inline size_t capacity() const noexcept;
-  /** The maximum capacity of this parser (the largest document it is allowed to process). */
-  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
-  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
-  /**
-   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
-   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
-   */
-  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
+  /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
+/* end file simdjson/generic/ondemand/value.h for lasx */
+/* including simdjson/generic/ondemand/logger.h for lasx: #include "simdjson/generic/ondemand/logger.h" */
+/* begin file simdjson/generic/ondemand/logger.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
+// that the call to the log functions be side-effect free. Thus, for example, you should not
+// create temporary std::string instances.
+namespace logger {
+
+enum class log_level : int32_t {
+  info = 0,
+  error = 1
+};
+
+#if SIMDJSON_VERBOSE_LOGGING
+  static constexpr const bool LOG_ENABLED = true;
+#else
+  static constexpr const bool LOG_ENABLED = false;
+#endif
+
+// We do not want these functions to be 'really inlined' since real inlining is
+// for performance purposes and if you are using the loggers, you do not care about
+// performance (or should not).
+static inline void log_headers() noexcept;
+// If args are provided, title will be treated as format string
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+template <typename... Args>
+static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
+static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
+static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
+static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
+static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
+static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
+
+} // namespace logger
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H
+/* end file simdjson/generic/ondemand/logger.h for lasx */
+/* including simdjson/generic/ondemand/token_iterator.h for lasx: #include "simdjson/generic/ondemand/token_iterator.h" */
+/* begin file simdjson/generic/ondemand/token_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
+/**
+ * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
+ * detected by stage 1.
+ *
+ * @private This is not intended for external use.
+ */
+class token_iterator {
+public:
   /**
-   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
-   * and `max_depth` depth.
-   *
-   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
-   * The document's instance current_depth() method should be used to monitor the parsing
-   * depth and limit it if desired.
+   * Create a new invalid token_iterator.
    *
-   * @param capacity The new capacity.
-   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
-   * @return The error, if there is one.
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
+  simdjson_inline token_iterator() noexcept = default;
+  simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
+  simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
+  simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
 
-  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * The parser instance can use threads when they are available to speed up some
-   * operations. It is enabled by default. Changing this attribute will change the
-   * behavior of the parser for future operations.
+   * Advance to the next token (returning the current one).
    */
-  bool threaded{true};
-  #else
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
   /**
-   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
+   * Reports the current offset in bytes from the start of the underlying buffer.
    */
-  bool threaded{false};
-  #endif
+  simdjson_inline uint32_t current_offset() const noexcept;
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result must be valid UTF-8.
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   * Get the JSON text for a given token (relative).
    *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * ## IMPORTANT: string_view lifetime
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    *
-   * The string_view is only valid as long as the bytes in dst.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used...
+   */
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
 
   /**
-   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
-   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
-   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
-   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
+   * Get the JSON text for a given token.
    *
-   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
-   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
-   * instead of get_raw_json_string()).
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * ## IMPORTANT: string_view lifetime
+   * @param position The position of the token.
    *
-   * The string_view is only valid as long as the bytes in dst.
+   */
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for a given token.
    *
-   * @param raw_json_string input
-   * @param dst A pointer to a buffer at least large enough to write this string as well as
-   *            an additional SIMDJSON_PADDING bytes.
-   * @return A string_view pointing at the unescaped string in dst
-   * @error STRING_ERROR if escapes are incorrect.
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token.
    */
-  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for a root token.
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param position The position of the token (start of the document).
+   */
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Return the current index.
+   */
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Reset to a previously saved index.
+   */
+  simdjson_inline void set_position(token_position target_position) noexcept;
+
+  // NOTE: we don't support a full C++ iterator interface, because we expect people to make
+  // different calls to advance the iterator based on *their own* state.
+
+  simdjson_inline bool operator==(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<(const token_iterator &other) const noexcept;
+  simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
+
+protected:
+  simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Returns true if string_buf_loc is outside of the allocated range for the
-   * the string buffer. When true, it indicates that the string buffer has overflowed.
-   * This is a development-time check that is not needed in production. It can be
-   * used to detect buffer overflows in the string buffer and usafe usage of the
-   * string buffer.
+   * Get the index of the JSON text for a given token (relative).
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = current token,
+   *              1 = next token, -1 = prev token.
    */
-  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
-#endif
+  simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
+  /**
+   * Get the index of the JSON text for a given token.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param position The position of the token.
+   *
+   */
+  simdjson_inline uint32_t peek_index(token_position position) const noexcept;
 
-private:
-  /** @private [for benchmarking access] The implementation to use */
-  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
-  size_t _capacity{0};
-  size_t _max_capacity;
-  size_t _max_depth{DEFAULT_MAX_DEPTH};
-  std::unique_ptr<uint8_t[]> string_buf{};
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  std::unique_ptr<token_position[]> start_positions{};
-#endif
+  const uint8_t *buf{};
+  token_position _position{};
 
   friend class json_iterator;
-  friend class document_stream;
+  friend class value_iterator;
+  friend class object;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
 };
 
 } // namespace ondemand
@@ -121099,28 +113700,27 @@ class parser {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::parser> : public lasx::implementation_simdjson_result_base<lasx::ondemand::parser> {
+struct simdjson_result<lasx::ondemand::token_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::token_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::parser &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::token_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
-/* end file simdjson/generic/ondemand/parser.h for lasx */
-
-// All other declarations
-/* including simdjson/generic/ondemand/array.h for lasx: #include "simdjson/generic/ondemand/array.h" */
-/* begin file simdjson/generic/ondemand/array.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H
+/* end file simdjson/generic/ondemand/token_iterator.h for lasx */
+/* including simdjson/generic/ondemand/json_iterator.h for lasx: #include "simdjson/generic/ondemand/json_iterator.h" */
+/* begin file simdjson/generic/ondemand/json_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
@@ -121128,180 +113728,311 @@ namespace lasx {
 namespace ondemand {
 
 /**
- * A forward-only JSON array.
+ * Iterates through JSON tokens, keeping track of depth and string buffer.
+ *
+ * @private This is not intended for external use.
  */
-class array {
+class json_iterator {
+protected:
+  token_iterator token{};
+  ondemand::parser *parser{};
+  /**
+   * Next free location in the string buffer.
+   *
+   * Used by raw_json_string::unescape() to have a place to unescape strings to.
+   */
+  uint8_t *_string_buf_loc{};
+  /**
+   * JSON error, if there is one.
+   *
+   * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
+   *
+   * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
+   * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
+   * this is not elided, we should make sure it's at least not using up a register. Failing that,
+   * we should store it in document so there's only one of them.
+   */
+  error_code error{SUCCESS};
+  /**
+   * Depth of the current token in the JSON.
+   *
+   * - 0 = finished with document
+   * - 1 = document root value (could be [ or {, not yet known)
+   * - 2 = , or } inside root array/object
+   * - 3 = key or value inside root array/object.
+   */
+  depth_t _depth{};
+  /**
+   * Beginning of the document indexes.
+   * Normally we have root == parser->implementation->structural_indexes.get()
+   * but this may differ, especially in streaming mode (where we have several
+   * documents);
+   */
+  token_position _root{};
+  /**
+   * Normally, a json_iterator operates over a single document, but in
+   * some cases, we may have a stream of documents. This attribute is meant
+   * as meta-data: the json_iterator works the same irrespective of the
+   * value of this attribute.
+   */
+  bool _streaming{false};
+
 public:
+  simdjson_inline json_iterator() noexcept = default;
+  simdjson_inline json_iterator(json_iterator &&other) noexcept;
+  simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
+  simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
+  simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
   /**
-   * Create a new invalid array.
+   * Skips a JSON value, whether it is a scalar, array or object.
+   */
+  simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
+
+  /**
+   * Tell whether the iterator is still at the start
+   */
+  simdjson_inline bool at_root() const noexcept;
+
+  /**
+   * Tell whether we should be expected to run in streaming
+   * mode (iterating over many documents). It is pure metadata
+   * that does not affect how the iterator works. It is used by
+   * start_root_array() and start_root_object().
+   */
+  simdjson_inline bool streaming() const noexcept;
+
+  /**
+   * Get the root value iterator
+   */
+  simdjson_inline token_position root_position() const noexcept;
+  /**
+   * Assert that we are at the document depth (== 1)
+   */
+  simdjson_inline void assert_at_document_depth() const noexcept;
+  /**
+   * Assert that we are at the root of the document
+   */
+  simdjson_inline void assert_at_root() const noexcept;
+
+  /**
+   * Tell whether the iterator is at the EOF mark
+   */
+  simdjson_inline bool at_end() const noexcept;
+
+  /**
+   * Tell whether the iterator is live (has not been moved).
+   */
+  simdjson_inline bool is_alive() const noexcept;
+
+  /**
+   * Abandon this iterator, setting depth to 0 (as if the document is finished).
+   */
+  simdjson_inline void abandon() noexcept;
+
+  /**
+   * Advance the current token without modifying depth.
+   */
+  simdjson_inline const uint8_t *return_current_and_advance() noexcept;
+
+  /**
+   * Returns true if there is a single token in the index (i.e., it is
+   * a JSON with a scalar value such as a single number).
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @return whether there is a single token
    */
-  simdjson_inline array() noexcept = default;
+  simdjson_inline bool is_single_token() const noexcept;
 
   /**
-   * Begin array iteration.
+   * Assert that there are at least the given number of tokens left.
    *
-   * Part of the std::iterable interface.
+   * Has no effect in release builds.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
+  simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
   /**
-   * Sentinel representing the end of the array.
+   * Assert that the given position addresses an actual token (is within bounds).
    *
-   * Part of the std::iterable interface.
+   * Has no effect in release builds.
    */
-  simdjson_inline simdjson_result<array_iterator> end() noexcept;
+  simdjson_inline void assert_valid_position(token_position position) const noexcept;
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * Get the JSON text for a given token (relative).
    *
-   * To check that an array is empty, it is more performant to use
-   * the is_empty() method.
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
   /**
-   * This method scans the beginning of the array and checks whether the
-   * array is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
+   * Get the maximum length of the JSON text for the current token (or relative).
+   *
+   * The length will include any whitespace at the end of the token.
+   *
+   * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
    */
-  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
+  simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the array. You should still consume values only once even if you
-   * can iterate through the array more than once. If you unescape a string
-   * within the array more than once, you have unsafe code. Note that rewinding
-   * an array means that you may need to reparse it anew: it is not a free
-   * operation.
+   * Get a pointer to the current location in the input buffer.
    *
-   * @returns true if the array contains some elements (not empty)
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * You may be pointing outside of the input buffer: it is not generally
+   * safe to dereference this pointer.
    */
-  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * Get the JSON text for a given token.
    *
-   *   ondemand::parser parser;
-   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/0/foo/a/1") == 20
+   * This is not null-terminated; it is a view into the JSON.
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
-   * instance: there is no rewind and no invalidation.
+   * @param position The position of the token to retrieve.
    *
-   * You may only call at_pointer on an array after it has been created, but before it has
-   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
-   * the location indicated by the JSON pointer (in case of success). It is no longer possible
-   * to call at_pointer on the same array.
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
+   */
+  simdjson_inline const uint8_t *peek(token_position position) const noexcept;
+  /**
+   * Get the maximum length of the JSON text for the current token (or relative).
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * The length will include any whitespace at the end of the token.
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   * @param position The position of the token to retrieve.
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-
+  simdjson_inline uint32_t peek_length(token_position position) const noexcept;
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * Get the maximum length of the JSON text for the current root token.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   * The length will include any whitespace at the end of the token.
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-  */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+   * @param position The position of the token to retrieve.
+   */
+  simdjson_inline uint32_t peek_root_length(token_position position) const noexcept;
+  /**
+   * Get the JSON text for the last token in the document.
+   *
+   * This is not null-terminated; it is a view into the JSON.
+   *
+   * TODO consider a string_view, assuming the length will get stripped out by the optimizer when
+   * it is not used ...
+   */
+  simdjson_inline const uint8_t *peek_last() const noexcept;
 
   /**
-   * Consumes the array and returns a string_view instance corresponding to the
-   * array as represented in JSON. It points inside the original document.
+   * Ascend one level.
+   *
+   * Validates that the depth - 1 == parent_depth.
+   *
+   * @param parent_depth the expected parent depth.
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
 
   /**
-   * Get the value at the given index. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * Descend one level.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * Validates that the new depth == child_depth.
+   *
+   * @param child_depth the expected child depth.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
-protected:
+  simdjson_inline void descend_to(depth_t child_depth) noexcept;
+  simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
+
   /**
-   * Go to the end of the array, no matter where you are right now.
+   * Get current depth.
    */
-  simdjson_inline error_code consume() noexcept;
+  simdjson_inline depth_t depth() const noexcept;
 
   /**
-   * Begin array iteration.
-   *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
+   * Get current (writeable) location in the string buffer.
    */
-  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  simdjson_inline uint8_t *&string_buf_loc() noexcept;
+
   /**
-   * Begin array iteration from the root.
+   * Report an unrecoverable error, preventing further iteration.
    *
-   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
-   *        resulting array.
-   * @error INCORRECT_TYPE if the iterator is not at [.
-   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
+
   /**
-   * Begin array iteration.
-   *
-   * This version of the method should be called after the initial [ has been verified, and is
-   * intended for use by switch statements that check the type of a value.
-   *
-   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   * Log error, but don't stop iteration.
+   * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
+   * @param message An error message to report with the error.
    */
-  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+  simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
+
+  /**
+   * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
+   * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
+   * The buffer (tmpbuf) is padded with space characters.
+   */
+  simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
+
+  simdjson_inline token_position position() const noexcept;
+  /**
+   * Write the raw_json_string to the string buffer and return a string_view.
+   * Each raw_json_string should be unescaped once, or else the string buffer might
+   * overflow.
+   */
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
+
+  simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
+
+  simdjson_inline error_code consume_character(char c) noexcept;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  simdjson_inline token_position start_position(depth_t depth) const noexcept;
+  simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
+#endif
+
+  /* Useful for debugging and logging purposes. */
+  inline std::string to_string() const noexcept;
 
   /**
-   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
-   *
-   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
-   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
-   *        into the resulting array.
+   * Returns the current location in the document if in bounds.
    */
-  simdjson_inline array(const value_iterator &iter) noexcept;
+  inline simdjson_result<const char *> current_location() const noexcept;
 
   /**
-   * Iterator marking current position.
-   *
-   * iter.is_alive() == false indicates iteration is complete.
+   * Updates this json iterator so that it is back at the beginning of the document,
+   * as if it had just been created.
    */
-  value_iterator iter{};
+  inline void rewind() noexcept;
+  /**
+   * This checks whether the {,},[,] are balanced so that the document
+   * ends with proper zero depth. This requires scanning the whole document
+   * and it may be expensive. It is expected that it will be rarely called.
+   * It does not attempt to match { with } and [ with ].
+   */
+  inline bool balanced() const noexcept;
+protected:
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /// The last token before the end
+  simdjson_inline token_position last_position() const noexcept;
+  /// The token *at* the end. This points at gibberish and should only be used for comparison.
+  simdjson_inline token_position end_position() const noexcept;
+  /// The end of the buffer.
+  simdjson_inline token_position end() const noexcept;
 
-  friend class value;
   friend class document;
-  friend struct simdjson_result<value>;
-  friend struct simdjson_result<array>;
-  friend class array_iterator;
-};
+  friend class document_stream;
+  friend class object;
+  friend class array;
+  friend class value;
+  friend class raw_json_string;
+  friend class parser;
+  friend class value_iterator;
+  friend class field;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
+  template <typename... Args>
+  friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
+}; // json_iterator
 
 } // namespace ondemand
 } // namespace lasx
@@ -121310,100 +114041,162 @@ class array {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::array> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array> {
+struct simdjson_result<lasx::ondemand::json_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::array &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::json_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() noexcept;
-  inline simdjson_result<size_t> count_elements() & noexcept;
-  inline simdjson_result<bool> is_empty() & noexcept;
-  inline simdjson_result<bool> reset() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
+  simdjson_inline simdjson_result() noexcept = default;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
-/* end file simdjson/generic/ondemand/array.h for lasx */
-/* including simdjson/generic/ondemand/array_iterator.h for lasx: #include "simdjson/generic/ondemand/array_iterator.h" */
-/* begin file simdjson/generic/ondemand/array_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H
+/* end file simdjson/generic/ondemand/json_iterator.h for lasx */
+/* including simdjson/generic/ondemand/json_type.h for lasx: #include "simdjson/generic/ondemand/json_type.h" */
+/* begin file simdjson/generic/ondemand/json_type.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * A forward-only JSON array.
- *
- * This is an input_iterator, meaning:
- * - It is forward-only
- * - * must be called exactly once per element.
- * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
+ * The type of a JSON value.
  */
-class array_iterator {
-public:
-  /** Create a new, invalid array iterator. */
-  simdjson_inline array_iterator() noexcept = default;
+enum class json_type {
+    // Start at 1 to catch uninitialized / default values more easily
+    array=1, ///< A JSON array   ( [ 1, 2, 3 ... ] )
+    object,  ///< A JSON object  ( { "a": 1, "b" 2, ... } )
+    number,  ///< A JSON number  ( 1 or -2.3 or 4.5e6 ...)
+    string,  ///< A JSON string  ( "a" or "hello world\n" ...)
+    boolean, ///< A JSON boolean (true or false)
+    null     ///< A JSON null    (null)
+};
 
-  //
-  // Iterator interface
-  //
+/**
+ * A type representing a JSON number.
+ * The design of the struct is deliberately straight-forward. All
+ * functions return standard values with no error check.
+ */
+struct number {
 
   /**
-   * Get the current element.
+   * return the automatically determined type of
+   * the number: number_type::floating_point_number,
+   * number_type::signed_integer or number_type::unsigned_integer.
    *
-   * Part of the std::iterator interface.
+   *    enum class number_type {
+   *        floating_point_number=1, /// a binary64 number
+   *        signed_integer,          /// a signed integer that fits in a 64-bit word using two's complement
+   *        unsigned_integer         /// a positive integer larger or equal to 1<<63
+   *    };
    */
-  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline ondemand::number_type get_number_type() const noexcept;
   /**
-   * Check if we are at the end of the JSON.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are no more elements in the JSON array.
+   * return true if the automatically determined type of
+   * the number is number_type::unsigned_integer.
    */
-  simdjson_inline bool operator==(const array_iterator &) const noexcept;
+  simdjson_inline bool is_uint64() const noexcept;
   /**
-   * Check if there are more elements in the JSON array.
-   *
-   * Part of the std::iterator interface.
-   *
-   * @return true if there are more elements in the JSON array.
+   * return the value as a uint64_t, only valid if is_uint64() is true.
    */
-  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  simdjson_inline uint64_t get_uint64() const noexcept;
+  simdjson_inline operator uint64_t() const noexcept;
+
   /**
-   * Move to the next element.
-   *
-   * Part of the std::iterator interface.
+   * return true if the automatically determined type of
+   * the number is number_type::signed_integer.
    */
-  simdjson_inline array_iterator &operator++() noexcept;
+  simdjson_inline bool is_int64() const noexcept;
+  /**
+   * return the value as a int64_t, only valid if is_int64() is true.
+   */
+  simdjson_inline int64_t get_int64() const noexcept;
+  simdjson_inline operator int64_t() const noexcept;
 
-private:
-  value_iterator iter{};
 
-  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+  /**
+   * return true if the automatically determined type of
+   * the number is number_type::floating_point_number.
+   */
+  simdjson_inline bool is_double() const noexcept;
+  /**
+   * return the value as a double, only valid if is_double() is true.
+   */
+  simdjson_inline double get_double() const noexcept;
+  simdjson_inline operator double() const noexcept;
 
-  friend class array;
-  friend class value;
-  friend struct simdjson_result<array_iterator>;
+  /**
+   * Convert the number to a double. Though it always succeed, the conversion
+   * may be lossy if the number cannot be represented exactly.
+   */
+  simdjson_inline double as_double() const noexcept;
+
+
+protected:
+  /**
+   * The next block of declaration is designed so that we can call the number parsing
+   * functions on a number type. They are protected and should never be used outside
+   * of the core simdjson library.
+   */
+  friend class value_iterator;
+  template<typename W>
+  friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
+  template<typename W>
+  friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
+  /** Store a signed 64-bit value to the number. */
+  simdjson_inline void append_s64(int64_t value) noexcept;
+  /** Store an unsigned 64-bit value to the number. */
+  simdjson_inline void append_u64(uint64_t value) noexcept;
+  /** Store a double value to the number. */
+  simdjson_inline void append_double(double value) noexcept;
+  /** Specifies that the value is a double, but leave it undefined. */
+  simdjson_inline void skip_double() noexcept;
+  /**
+   * End of friend declarations.
+   */
+
+  /**
+   * Our attributes are a union type (size = 64 bits)
+   * followed by a type indicator.
+   */
+  union {
+    double floating_point_number;
+    int64_t signed_integer;
+    uint64_t unsigned_integer;
+  } payload{0};
+  number_type type{number_type::signed_integer};
 };
 
+/**
+ * Write the JSON type to the output stream
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ */
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
+
+#if SIMDJSON_EXCEPTIONS
+/**
+ * Send JSON type to an output stream.
+ *
+ * @param out The output stream.
+ * @param type The json_type.
+ * @throw simdjson_error if the result being printed has an error. If there is an error with the
+ *        underlying output stream, that error will be propagated (simdjson_error will not be
+ *        thrown).
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
+#endif
+
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
@@ -121411,1550 +114204,1341 @@ class array_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::array_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator> {
+struct simdjson_result<lasx::ondemand::json_type> : public lasx::implementation_simdjson_result_base<lasx::ondemand::json_type> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::array_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::json_type &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-
-  //
-  // Iterator interface
-  //
-
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &operator++() noexcept;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
-/* end file simdjson/generic/ondemand/array_iterator.h for lasx */
-/* including simdjson/generic/ondemand/document.h for lasx: #include "simdjson/generic/ondemand/document.h" */
-/* begin file simdjson/generic/ondemand/document.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H
+/* end file simdjson/generic/ondemand/json_type.h for lasx */
+/* including simdjson/generic/ondemand/raw_json_string.h for lasx: #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * A JSON document. It holds a json_iterator instance.
+ * A string escaped per JSON rules, terminated with quote ("). They are used to represent
+ * unescaped keys inside JSON documents.
  *
- * Used by tokens to get text, and string buffer location.
+ * (In other words, a pointer to the beginning of a string, just after the start quote, inside a
+ * JSON file.)
  *
- * You must keep the document around during iteration.
- */
-class document {
-public:
-  /**
-   * Create a new invalid document.
-   *
-   * Exists so you can declare a variable and later assign to it before use.
-   */
-  simdjson_inline document() noexcept = default;
-  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
-  simdjson_inline document(document &&other) noexcept = default;
-  simdjson_inline document &operator=(const document &other) noexcept = delete;
-  simdjson_inline document &operator=(document &&other) noexcept = default;
-
-  /**
-   * Cast this JSON value to an array.
-   *
-   * @returns An object that can be used to iterate the array.
-   * @returns INCORRECT_TYPE If the JSON value is not an array.
-   */
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  /**
-   * Cast this JSON value to an object.
-   *
-   * @returns An object that can be used to look up or iterate fields.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   */
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  /**
-   * Cast this JSON value to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to an unsigned integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
-   */
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  /**
-   * Cast this JSON value (inside string) to a signed integer.
-   *
-   * @returns A signed 64-bit integer.
-   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  /**
-   * Cast this JSON value to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-
-  /**
-   * Cast this JSON value (inside string) to a double.
-   *
-   * @returns A double.
-   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
-   */
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: Calling get_string() twice on the same document is an error.
-   *
-   * @param Whether to allow a replacement character for unmatched surrogate pairs.
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  /**
-   * Attempts to fill the provided std::string reference with the parsed value of the current string.
-   *
-   * The string is guaranteed to be valid UTF-8.
-   *
-   * Important: a value should be consumed once. Calling get_string() twice on the same value
-   * is an error.
-   *
-   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
-   * We recommend you avoid allocating an std::string unless you need to.
-   *
-   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
-   */
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  /**
-   * Cast this JSON value to a string.
-   *
-   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
-   *
-   * Important: Calling get_wobbly_string() twice on the same document is an error.
-   *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  /**
-   * Cast this JSON value to a raw_json_string.
-   *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
-   *
-   * @returns A pointer to the raw JSON for the given string.
-   * @returns INCORRECT_TYPE if the JSON value is not a string.
-   */
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @returns INCORRECT_TYPE if the JSON value is not true or false.
-   */
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
-   * by default), and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value if a JSON array or object cannot be found.
-   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
-   */
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  /**
-   * Checks if this JSON value is null.  If and only if the value is
-   * null, then it is consumed (we advance). If we find a token that
-   * begins with 'n' but is not 'null', then an error is returned.
-   *
-   * @returns Whether the value is null.
-   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
-   */
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
-   *
-   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
-   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
-   *
-   * @returns A value of the given type, parsed from the JSON.
-   * @returns INCORRECT_TYPE If the JSON value is not the given type.
-   */
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  /**
-   * @overload template<typename T> simdjson_result<T> get() & noexcept
-   *
-   * We disallow the use tag_invoke CPO on a moved document; it may create UB
-   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
-   *
-   * The member function is still remains specialize-able for compatibility
-   * reasons, but we completely disallow its use when a tag_invoke customization
-   * is provided.
-   */
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
-
-  /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
-   */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
-
-#if SIMDJSON_EXCEPTIONS
+ * This class is deliberately simplistic and has little functionality. You can
+ * compare a raw_json_string instance with an unescaped C string, but
+ * that is nearly all you can do.
+ *
+ * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
+ * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
+ * instance. Doing so requires you to have a sufficiently large buffer.
+ *
+ * The raw_json_string instances originate typically from field instance which in turn represent
+ * key-value pairs from object instances. From a field instance, you get the raw_json_string
+ * instance by calling key(). You can, if you want a more usable string_view instance, call
+ * the unescaped_key() method on the field instance. You may also create a raw_json_string from
+ * any other string value, with the value.get_raw_json_string() method. Again, you can get
+ * a more usable string_view instance by calling get_string().
+ *
+ */
+class raw_json_string {
+public:
   /**
-   * Cast this JSON value to an instance of type T. The programmer is responsible for
-   * providing an implementation of get<T> for the type T, if T is not one of the types
-   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
-   *
-   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   * Create a new invalid raw_json_string.
    *
-   * @returns An instance of type T
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  template <class T>
-  explicit simdjson_inline operator T() & noexcept(false);
-  template <class T>
-  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
+  simdjson_inline raw_json_string() noexcept = default;
 
   /**
-   * Cast this JSON value to an array.
+   * Create a new invalid raw_json_string pointed at the given location in the JSON.
    *
-   * @returns An object that can be used to iterate the array.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
-   */
-  simdjson_inline operator array() & noexcept(false);
-  /**
-   * Cast this JSON value to an object.
+   * The given location must be just *after* the beginning quote (") in the JSON file.
    *
-   * @returns An object that can be used to look up or iterate fields.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   * It *must* be terminated by a ", and be a valid JSON string.
    */
-  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
   /**
-   * Cast this JSON value to an unsigned integer.
+   * Get the raw pointer to the beginning of the string in the JSON (just after the ").
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   * It is possible for this function to return a null pointer if the instance
+   * has outlived its existence.
    */
-  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline const char * raw() const noexcept;
+
   /**
-   * Cast this JSON value to a signed integer.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done) on target.size() characters,
+   * and if the raw_json_string instance has a quote character at byte index target.size().
+   * We never read more than length + 1 bytes in the raw_json_string instance.
+   * If length is smaller than target.size(), this will return false.
    *
-   * @returns A signed 64-bit integer.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
-   */
-  simdjson_inline operator int64_t() noexcept(false);
-  /**
-   * Cast this JSON value to a double.
+   * The std::string_view instance may contain any characters. However, the caller
+   * is responsible for setting length so that length bytes may be read in the
+   * raw_json_string.
    *
-   * @returns A double.
-   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   * Performance: the comparison may be done using memcmp which may be efficient
+   * for long strings.
    */
-  simdjson_inline operator double() noexcept(false);
+  simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
+
   /**
-   * Cast this JSON value to a string.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The std::string_view instance should not contain unescaped quote characters:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * The string is guaranteed to be valid UTF-8.
+   * Performance: the comparison is done byte-by-byte which might be inefficient for
+   * long strings.
    *
-   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
-   *          time it parses a document or when it is destroyed.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
+   *
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
+
   /**
-   * Cast this JSON value to a raw_json_string.
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
+   * The provided C string should not contain an unescaped quote character:
+   * the caller is responsible for this check. See is_free_from_unescaped_quote.
    *
-   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   * If target is a compile-time constant, and your compiler likes you,
+   * you should be able to do the following without performance penalty...
    *
-   * @returns A pointer to the raw JSON for the given string.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   *   static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
+   *   s.unsafe_is_equal(target);
    */
-  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
+
   /**
-   * Cast this JSON value to a bool.
-   *
-   * @returns A bool value.
-   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   * This compares the current instance to the std::string_view target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline bool is_equal(std::string_view target) const noexcept;
+
   /**
-   * Cast this JSON value to a value when the document is an object or an array.
-   *
-   * You must not have begun iterating through the object or array. When
-   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
-   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
-   * rewind() to reset the document to its initial state before calling this method.
-   *
-   * @returns A value value if a JSON array or object cannot be found.
-   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   * This compares the current instance to the C string target: returns true if
+   * they are byte-by-byte equal (no escaping is done).
    */
-  simdjson_inline operator value() noexcept(false);
-#endif
+  simdjson_inline bool is_equal(const char* target) const noexcept;
+
   /**
-   * This method scans the array and counts the number of elements.
-   * The count_elements method should always be called before you have begun
-   * iterating through the array: it is expected that you are pointing at
-   * the beginning of the array.
-   * The runtime complexity is linear in the size of the array. After
-   * calling this function, if successful, the array is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue. Note that count_elements() does not validate the JSON values,
-   * only the structure of the array.
+   * Returns true if target is free from unescaped quote. If target is known at
+   * compile-time, we might expect the computation to happen at compile time with
+   * many compilers (not all!).
    */
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-   /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
+  static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
+  static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
+
+private:
+
+
+  /**
+   * This will set the inner pointer to zero, effectively making
+   * this instance unusable.
    */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline void consume() noexcept { buf = nullptr; }
+
   /**
-   * Get the value at the given index in the array. This function has linear-time complexity.
-   * This function should only be called once on an array instance since the array iterator is not reset between each call.
+   * Checks whether the inner pointer is non-null and thus usable.
+   */
+  simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
+
+  /**
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result will be a valid UTF-8.
    *
-   * @return The value at the given index, or:
-   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
+   * @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
    */
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
+
   /**
-   * Begin array iteration.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc.
+   * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
    *
-   * Part of the std::iterable interface.
+   * ## IMPORTANT: string_view lifetime
+   *
+   * The string_view is only valid until the next parse() call on the parser.
+   *
+   * @param iter A json_iterator, which contains a buffer where the string will be written.
    */
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
+  const uint8_t * buf{};
+  friend class object;
+  friend class field;
+  friend class parser;
+  friend struct simdjson_result<raw_json_string>;
+};
+
+simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
+
+/**
+ * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
+ * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
+ */
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
+simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
+
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+template<>
+struct simdjson_result<lasx::ondemand::raw_json_string> : public lasx::implementation_simdjson_result_base<lasx::ondemand::raw_json_string> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::raw_json_string &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline ~simdjson_result() noexcept = default; ///< @private
+
+  simdjson_inline simdjson_result<const char *> raw() const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept;
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
+/* end file simdjson/generic/ondemand/raw_json_string.h for lasx */
+/* including simdjson/generic/ondemand/parser.h for lasx: #include "simdjson/generic/ondemand/parser.h" */
+/* begin file simdjson/generic/ondemand/parser.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+#include <memory>
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+/**
+ * The default batch size for document_stream instances for this On-Demand kernel.
+ * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value
+ * in the future.
+ */
+static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
+/**
+ * Some adversary might try to set the batch size to 0 or 1, which might cause problems.
+ * We set a minimum of 32B since anything else is highly likely to be an error. In practice,
+ * most users will want a much larger batch size.
+ *
+ * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
+ * document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
+ */
+static constexpr size_t MINIMAL_BATCH_SIZE = 32;
+
+/**
+ * A JSON fragment iterator.
+ *
+ * This holds the actual iterator as well as the buffer for writing strings.
+ */
+class parser {
+public:
   /**
-   * Sentinel representing the end of the array.
+   * Create a JSON parser.
    *
-   * Part of the std::iterable interface.
+   * The new parser will have zero capacity.
    */
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
+
+  inline parser(parser &&other) noexcept = default;
+  simdjson_inline parser(const parser &other) = delete;
+  simdjson_inline parser &operator=(const parser &other) = delete;
+  simdjson_inline parser &operator=(parser &&other) noexcept = default;
+
+  /** Deallocate the JSON parser. */
+  inline ~parser() noexcept = default;
 
   /**
-   * Look up a field by name on an object (order-sensitive).
+   * Start iterating an on-demand JSON document.
    *
-   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
-   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *   ondemand::parser parser;
+   *   document doc = parser.iterate(json);
    *
-   * ```c++
-   * simdjson::ondemand::parser parser;
-   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
-   * double z = obj.find_field("z");
-   * double y = obj.find_field("y");
-   * double x = obj.find_field("x");
-   * ```
+   * It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
+   * Otherwise the iterate method may return an error. In particular, the whole input should be
+   * valid: we do not attempt to tolerate incorrect content either before or after a JSON
+   * document. If there is a UTF-8 BOM, the parser skips it.
    *
-   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
-   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   * ### IMPORTANT: Validate what you use
    *
+   * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
+   * iterate does not parse and validate the whole document.
    *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * ### IMPORTANT: Buffer Lifetime
    *
-   * You are expected to access keys only once. You should access the value corresponding to
-   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
-   * is an error.
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-
-  /**
-   * Look up a field by name on an object, without regard to key order.
+   * ### IMPORTANT: Document Lifetime
    *
-   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
-   * and often appears negligible. It starts out normally, starting out at the last field; but if
-   * the field is not found, it scans from the beginning of the object to see if it missed it. That
-   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
-   * in question is large. The fact that the extra code is there also bumps the executable size.
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
    *
-   * It is the default, however, because it would be highly surprising (and hard to debug) if the
-   * default behavior failed to look up a field just because it was in the wrong order--and many
-   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   * ### REQUIRED: Buffer Padding
    *
-   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
-   * field was not there when they are not in order).
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. E.g., the array
-   * given by content["bids"].get_array() should not be accessed after you have called
-   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
-   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
-   * OUT_OF_ORDER_ITERATION error is generated.
+   * ### std::string references
    *
-   * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
-   * is an error.
+   * If you pass a mutable std::string reference (std::string&), the parser will seek to extend
+   * its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
    *
-   * @param key The key to look up.
-   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
-   */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
- simdjson_result<value> operator[](int) & noexcept = delete;
-
-  /**
-   * Get the type of this JSON value. It does not validate or consume the value.
-   * E.g., you must still call "is_null()" to check that a value is null even if
-   * "type()" returns json_type::null.
+   * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
+   * the string but before the end of the allocated memory (std::string::capacity()).
+   * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
+   * container-overflow checks, you may encounter sanitizer warnings.
+   * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
+   * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
+   * which can be be passed to the parser's iterate function:
    *
-   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
-   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
-   * let it throw an exception).
+   *    std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
+   *    document doc = parser.iterate(simdjson::pad(json));
    *
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
-   */
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-
-  /**
-   * Checks whether the document is a scalar (string, number, null, Boolean).
-   * Returns false when there it is an array or object.
+   * @param json The JSON to parse.
+   * @param len The length of the JSON.
+   * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
    *
-   * @returns true if the type is string, number, null, Boolean
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * @return The document, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
+  /** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
+  simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
 
   /**
-   * Checks whether the document is a string.
+   * @private
    *
-   * @returns true if the type is string
-   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   * Start iterating an on-demand JSON document.
+   *
+   *   ondemand::parser parser;
+   *   json_iterator doc = parser.iterate(json);
+   *
+   * ### IMPORTANT: Buffer Lifetime
+   *
+   * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
+   * long as the document iteration.
+   *
+   * ### IMPORTANT: Document Lifetime
+   *
+   * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
+   * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
+   * you call parse() again or destroy the parser.
+   *
+   * The ondemand::document instance holds the iterator. The document must remain in scope
+   * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array.
+   *
+   * ### REQUIRED: Buffer Padding
+   *
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
+   *
+   * @param json The JSON to parse.
+   *
+   * @return The iterator, or an error:
+   *         - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
+   *         - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
+   *           allocation fails.
+   *         - EMPTY if the document is all whitespace.
+   *         - UTF8_ERROR if the document is not valid UTF-8.
+   *         - UNESCAPED_CHARS if a string contains control characters that must be escaped
+   *         - UNCLOSED_STRING if there is an unclosed string in the document.
    */
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
+
 
   /**
-   * Checks whether the document is a negative number.
+   * Parse a buffer containing many JSON documents.
    *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline bool is_negative() noexcept;
-  /**
-   * Checks whether the document is an integer number. Note that
-   * this requires to partially parse the number string. If
-   * the value is determined to be an integer, it may still
-   * not parse properly as an integer in subsequent steps
-   * (e.g., it might overflow).
+   *   auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
+   *   ondemand::parser parser;
+   *   ondemand::document_stream docs = parser.iterate_many(json);
+   *   for (auto & doc : docs) {
+   *     std::cout << doc["foo"] << std::endl;
+   *   }
+   *   // Prints 1 2 3
    *
-   * @returns true if the number if negative.
-   */
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  /**
-   * Determine the number type (integer or floating-point number) as quickly
-   * as possible. This function does not fully validate the input. It is
-   * useful when you only need to classify the numbers, without parsing them.
+   * No copy of the input buffer is made.
+   *
+   * The function is lazy: it may be that no more than one JSON document at a time is parsed.
    *
-   * If you are planning to retrieve the value or you need full validation,
-   * consider using the get_number() method instead: it will fully parse
-   * and validate the input, and give you access to the type:
-   * get_number().get_number_type().
+   * The caller is responsabile to ensure that the input string data remains unchanged and is
+   * not deleted during the loop.
    *
-   * get_number_type() is number_type::unsigned_integer if we have
-   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
-   * get_number_type() is number_type::signed_integer if we have an
-   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
-   * get_number_type() is number_type::big_integer if we have an integer outside
-   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
-   * Otherwise, get_number_type() has value number_type::floating_point_number
+   * ### Format
    *
-   * This function requires processing the number string, but it is expected
-   * to be faster than get_number().get_number_type() because it is does not
-   * parse the number value.
+   * The buffer must contain a series of one or more JSON documents, concatenated into a single
+   * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
+   * then starts parsing the next document at that point. (It does this with more parallelism and
+   * lookahead than you might think, though.)
    *
-   * @returns the type of the number
-   */
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-
-  /**
-   * Attempt to parse an ondemand::number. An ondemand::number may
-   * contain an integer value or a floating-point value, the simdjson
-   * library will autodetect the type. Thus it is a dynamically typed
-   * number. Before accessing the value, you must determine the detected
-   * type.
+   * documents that consist of an object or array may omit the whitespace between them, concatenating
+   * with no separator. Documents that consist of a single primitive (i.e. documents that are not
+   * arrays or objects) MUST be separated with ASCII whitespace.
    *
-   * number.get_number_type() is number_type::signed_integer if we have
-   * an integer in [-9223372036854775808,9223372036854775808)
-   * You can recover the value by calling number.get_int64() and you
-   * have that number.is_int64() is true.
+   * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
+   * If there is a UTF-8 BOM, the parser skips it.
    *
-   * number.get_number_type() is number_type::unsigned_integer if we have
-   * an integer in [9223372036854775808,18446744073709551616)
-   * You can recover the value by calling number.get_uint64() and you
-   * have that number.is_uint64() is true.
+   * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
+   * Setting batch_size to excessively large or excessively small values may impact negatively the
+   * performance.
    *
-   * Otherwise, number.get_number_type() has value number_type::floating_point_number
-   * and we have a binary64 number.
-   * You can recover the value by calling number.get_double() and you
-   * have that number.is_double() is true.
+   * ### REQUIRED: Buffer Padding
    *
-   * You must check the type before accessing the value: it is an error
-   * to call "get_int64()" when number.get_number_type() is not
-   * number_type::signed_integer and when number.is_int64() is false.
-   */
-  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
-
-  /**
-   * Get the raw JSON for this token.
+   * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
+   * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
+   * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
+   * SIMDJSON_PADDING bytes to avoid runtime warnings.
    *
-   * The string_view will always point into the input buffer.
+   * ### Threads
    *
-   * The string_view will start at the beginning of the token, and include the entire token
-   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
-   * string token always begins with a " and is always terminated by the final ", possibly
-   * followed by a number of spaces.
+   * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
+   * hood to do some lookahead.
    *
-   * The string_view is *not* null-terminated. If this is a scalar (string, number,
-   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   * ### Parser Capacity
    *
-   * Tokens include:
-   * - {
-   * - [
-   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
-   * - -1.2e-100
-   * - true
-   * - false
-   * - null
+   * If the parser's current capacity is less than batch_size, it will allocate enough capacity
+   * to handle it (up to max_capacity).
+   *
+   * @param buf The concatenated JSON to parse.
+   * @param len The length of the concatenated JSON.
+   * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
+   *                   spot is cache-related: small enough to fit in cache, yet big enough to
+   *                   parse as many documents as possible in one tight loop.
+   *                   Defaults to 10MB, which has been a reasonable sweet spot in our tests.
+   * @param allow_comma_separated (defaults on false) This allows a mode where the documents are
+   *                   separated by commas instead of whitespace. It comes with a performance
+   *                   penalty because the entire document is indexed at once (and the document must be
+   *                   less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter
+   *                   is effectively ignored, as it is set to at least the document size.
+   * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors:
+   *         - MEMALLOC if the parser does not have enough capacity and memory allocation fails
+   *         - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
+   *         - other json errors if parsing fails. You should not rely on these errors to always the same for the
+   *           same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
    */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  inline simdjson_result<document_stream> iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
+  /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */
+  inline simdjson_result<document_stream> iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept;
+  inline simdjson_result<document_stream> iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe
 
+  /** @private We do not want to allow implicit conversion from C string to std::string. */
+  simdjson_result<document_stream> iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
+
+  /** The capacity of this parser (the largest document it can process). */
+  simdjson_pure simdjson_inline size_t capacity() const noexcept;
+  /** The maximum capacity of this parser (the largest document it is allowed to process). */
+  simdjson_pure simdjson_inline size_t max_capacity() const noexcept;
+  simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
   /**
-   * Reset the iterator inside the document instance so we are pointing back at the
-   * beginning of the document, as if it had just been created. It invalidates all
-   * values, objects and arrays that you have created so far (including unescaped strings).
-   */
-  inline void rewind() noexcept;
-  /**
-   * Returns debugging information.
-   */
-  inline std::string to_debug_string() noexcept;
-  /**
-   * Some unrecoverable error conditions may render the document instance unusable.
-   * The is_alive() method returns true when the document is still suitable.
+   * The maximum depth of this parser (the most deeply nested objects and arrays it can process).
+   * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
    */
-  inline bool is_alive() noexcept;
+  simdjson_pure simdjson_inline size_t max_depth() const noexcept;
 
   /**
-   * Returns the current location in the document if in bounds.
+   * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
+   * and `max_depth` depth.
+   *
+   * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
+   * The document's instance current_depth() method should be used to monitor the parsing
+   * depth and limit it if desired.
+   *
+   * @param capacity The new capacity.
+   * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
+   * @return The error, if there is one.
    */
-  inline simdjson_result<const char *> current_location() const noexcept;
+  simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
 
+  #ifdef SIMDJSON_THREADS_ENABLED
   /**
-   * Returns true if this document has been fully parsed.
-   * If you have consumed the whole document and at_end() returns
-   * false, then there may be trailing content.
+   * The parser instance can use threads when they are available to speed up some
+   * operations. It is enabled by default. Changing this attribute will change the
+   * behavior of the parser for future operations.
    */
-  inline bool at_end() const noexcept;
-
+  bool threaded{true};
+  #else
   /**
-   * Returns the current depth in the document if in bounds.
-   *
-   * E.g.,
-   *  0 = finished with document
-   *  1 = document root value (could be [ or {, not yet known)
-   *  2 = , or } inside root array/object
-   *  3 = key or value inside root array/object.
+   * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
    */
-  simdjson_inline int32_t current_depth() const noexcept;
-
+  bool threaded{false};
+  #endif
   /**
-   * Get the value associated with the given JSON pointer.  We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard.
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/foo/a/1") == 20
-   *
-   * It is allowed for a key to be the empty string:
-   *
-   *   ondemand::parser parser;
-   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("//a/1") == 20
-   *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result must be valid UTF-8.
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_pointer("/\\u00E9") == 123
-   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * Note that at_pointer() automatically calls rewind between each call. Thus
-   * all values, objects and arrays that you have created so far (including unescaped strings)
-   * are invalidated. After calling at_pointer, you need to consume the result: string values
-   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
-   * structures and so forth.
+   * ## IMPORTANT: string_view lifetime
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
+   * The string_view is only valid as long as the bytes in dst.
    *
-   * @return The value associated with the given JSON pointer, or:
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
-   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
 
   /**
-   * Get the value associated with the given JSONPath expression. We only support
-   * JSONPath queries that trivially convertible to JSON Pointer queries: key
-   * names and array indices.
+   * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
+   * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   * The provided pointer is advanced to the end of the string by reference, and a string_view instance
+   * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
+   * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
    *
-   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   * This unescape function is a low-level function. If you want a more user-friendly approach, you should
+   * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
+   * instead of get_raw_json_string()).
    *
-   * Key values are matched exactly, without unescaping or Unicode normalization.
-   * We do a byte-by-byte comparison. E.g.
+   * ## IMPORTANT: string_view lifetime
    *
-   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
-   *   auto doc = parser.iterate(json);
-   *   doc.at_path(".\\u00E9") == 123
-   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   * The string_view is only valid as long as the bytes in dst.
    *
-   * @return The value associated with the given JSONPath expression, or:
-   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
-   *         - NO_SUCH_FIELD if a field does not exist in an object
-   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
-   *         - INCORRECT_TYPE if a non-integer is used to access an array
-   */
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
-
-  /**
-   * Consumes the document and returns a string_view instance corresponding to the
-   * document as represented in JSON. It points inside the original byte array containing
-   * the JSON document.
-   */
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-protected:
-  /**
-   * Consumes the document.
+   * @param raw_json_string input
+   * @param dst A pointer to a buffer at least large enough to write this string as well as
+   *            an additional SIMDJSON_PADDING bytes.
+   * @return A string_view pointing at the unescaped string in dst
+   * @error STRING_ERROR if escapes are incorrect.
    */
-  simdjson_inline error_code consume() noexcept;
-
-  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
-  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
-
-  simdjson_inline value_iterator resume_value_iterator() noexcept;
-  simdjson_inline value_iterator get_root_value_iterator() noexcept;
-  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
-  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
-
-  //
-  // Fields
-  //
-  json_iterator iter{}; ///< Current position in the document
-  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
-
-  friend class array_iterator;
-  friend class value;
-  friend class ondemand::parser;
-  friend class object;
-  friend class array;
-  friend class field;
-  friend class token;
-  friend class document_stream;
-  friend class document_reference;
-};
-
-
-/**
- * A document_reference is a thin wrapper around a document reference instance.
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents. They differ from document instances when parsing a scalar value
- * (a document that is not an array or an object). In the case of a document,
- * we expect the document to be fully consumed. In the case of a document_reference,
- * we allow trailing content.
- */
-class document_reference {
-public:
-  simdjson_inline document_reference() noexcept;
-  simdjson_inline document_reference(document &d) noexcept;
-  simdjson_inline document_reference(const document_reference &other) noexcept = default;
-  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
-  simdjson_inline void rewind() noexcept;
-  simdjson_inline simdjson_result<array> get_array() & noexcept;
-  simdjson_inline simdjson_result<object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<value> get_value() noexcept;
-
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-  template <typename T>
-  simdjson_inline simdjson_result<T> get() &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
-    T out{};
-    SIMDJSON_TRY(get<T>(out));
-    return out;
-  }
-  template<typename T>
-  simdjson_inline simdjson_result<T> get() &&
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
-#else
-    noexcept
-#endif
-  {
-      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
-      return static_cast<document&>(*this).get<T>();
-  }
+  simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept;
 
+#if SIMDJSON_DEVELOPMENT_CHECKS
   /**
-   * Get this value as the given type.
-   *
-   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
-   *
-   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
-   *
-   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
-   * @returns INCORRECT_TYPE If the JSON value is not an object.
-   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   * Returns true if string_buf_loc is outside of the allocated range for the
+   * the string buffer. When true, it indicates that the string buffer has overflowed.
+   * This is a development-time check that is not needed in production. It can be
+   * used to detect buffer overflows in the string buffer and usafe usage of the
+   * string buffer.
    */
-  template<typename T>
-  simdjson_inline error_code get(T &out) &
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
-#else
-    noexcept
-#endif
-  {
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    if constexpr (custom_deserializable<T, document_reference>) {
-        return deserialize(*this, out);
-    } else {
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-      // Unless the simdjson library or the user provides an inline implementation, calling this method should
-      // immediately fail.
-      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
-        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
-        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
-        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
-        " You may also add support for custom types, see our documentation.");
-      static_cast<void>(out); // to get rid of unused errors
-      return UNINITIALIZED;
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
-    }
-#endif
-  }
-  /** @overload template<typename T> error_code get(T &out) & noexcept */
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-  simdjson_inline operator document&() const noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator array() & noexcept(false);
-  simdjson_inline operator object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator value() noexcept(false);
+  bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept;
 #endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
-  simdjson_result<value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
-
-  simdjson_inline simdjson_result<json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<number> get_number() noexcept;
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
 private:
-  document *doc{nullptr};
-};
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::document> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::document &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lasx::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline int32_t current_depth() const noexcept;
-  simdjson_inline bool at_end() const noexcept;
-  simdjson_inline bool is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  /** @private [for benchmarking access] The implementation to use */
+  std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
+  size_t _capacity{0};
+  size_t _max_capacity;
+  size_t _max_depth{DEFAULT_MAX_DEPTH};
+  std::unique_ptr<uint8_t[]> string_buf{};
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  std::unique_ptr<token_position[]> start_positions{};
+#endif
 
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  friend class json_iterator;
+  friend class document_stream;
 };
 
-
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-
-
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_reference> {
+struct simdjson_result<lasx::ondemand::parser> : public lasx::implementation_simdjson_result_base<lasx::ondemand::parser> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result(lasx::ondemand::parser &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
-  simdjson_inline error_code rewind() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
-  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
-  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
-  simdjson_inline simdjson_result<double> get_double() noexcept;
-  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
-  template <typename string_type>
-  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
-  simdjson_inline simdjson_result<bool> get_bool() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
-  simdjson_inline simdjson_result<bool> is_null() noexcept;
-
-  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
-  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
-
-  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
-  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
-#if SIMDJSON_EXCEPTIONS
-  template <class T>
-  explicit simdjson_inline operator T() noexcept(false);
-  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
-  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
-  simdjson_inline operator uint64_t() noexcept(false);
-  simdjson_inline operator int64_t() noexcept(false);
-  simdjson_inline operator double() noexcept(false);
-  simdjson_inline operator std::string_view() noexcept(false);
-  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
-  simdjson_inline operator bool() noexcept(false);
-  simdjson_inline operator lasx::ondemand::value() noexcept(false);
-#endif
-  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
-  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
-  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
-  simdjson_inline simdjson_result<bool> is_string() noexcept;
-  simdjson_inline simdjson_result<const char *> current_location() noexcept;
-  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
-  simdjson_inline simdjson_result<bool> is_negative() noexcept;
-  simdjson_inline simdjson_result<bool> is_integer() noexcept;
-  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
-  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
-  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
-
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
 };
 
-
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
-/* end file simdjson/generic/ondemand/document.h for lasx */
-/* including simdjson/generic/ondemand/document_stream.h for lasx: #include "simdjson/generic/ondemand/document_stream.h" */
-/* begin file simdjson/generic/ondemand/document_stream.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H
+/* end file simdjson/generic/ondemand/parser.h for lasx */
+
+// All other declarations
+/* including simdjson/generic/ondemand/array.h for lasx: #include "simdjson/generic/ondemand/array.h" */
+/* begin file simdjson/generic/ondemand/array.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#ifdef SIMDJSON_THREADS_ENABLED
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#endif
-
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-/** @private Custom worker class **/
-struct stage1_worker {
-  stage1_worker() noexcept = default;
-  stage1_worker(const stage1_worker&) = delete;
-  stage1_worker(stage1_worker&&) = delete;
-  stage1_worker operator=(const stage1_worker&) = delete;
-  ~stage1_worker();
-  /**
-   * We only start the thread when it is needed, not at object construction, this may throw.
-   * You should only call this once.
-   **/
-  void start_thread();
+/**
+ * A forward-only JSON array.
+ */
+class array {
+public:
   /**
-   * Start a stage 1 job. You should first call 'run', then 'finish'.
-   * You must call start_thread once before.
+   * Create a new invalid array.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
    */
-  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
-  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
-  void finish();
-
-private:
-
-  /**
-   * Normally, we would never stop the thread. But we do in the destructor.
-   * This function is only safe assuming that you are not waiting for results. You
-   * should have called run, then finish, and be done.
-   **/
-  void stop_thread();
+  simdjson_inline array() noexcept = default;
 
-  std::thread thread{};
-  /** These three variables define the work done by the thread. **/
-  ondemand::parser * stage1_thread_parser{};
-  size_t _next_batch_start{};
-  document_stream * owner{};
   /**
-   * We have two state variables. This could be streamlined to one variable in the future but
-   * we use two for clarity.
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
    */
-  bool has_work{false};
-  bool can_work{true};
-
+  simdjson_inline simdjson_result<array_iterator> begin() noexcept;
   /**
-   * We lock using a mutex.
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
    */
-  std::mutex locking_mutex{};
-  std::condition_variable cond_var{};
-
-  friend class document_stream;
-};
-#endif  // SIMDJSON_THREADS_ENABLED
-
-/**
- * A forward-only stream of documents.
- *
- * Produced by parser::iterate_many.
- *
- */
-class document_stream {
-public:
+  simdjson_inline simdjson_result<array_iterator> end() noexcept;
   /**
-   * Construct an uninitialized document_stream.
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
    *
-   *  ```c++
-   *  document_stream docs;
-   *  auto error = parser.iterate_many(json).get(docs);
-   *  ```
+   * To check that an array is empty, it is more performant to use
+   * the is_empty() method.
    */
-  simdjson_inline document_stream() noexcept;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream(document_stream &&other) noexcept = default;
-  /** Move one document_stream to another. */
-  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
-
-  simdjson_inline ~document_stream() noexcept;
-
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
   /**
-   * Returns the input size in bytes.
+   * This method scans the beginning of the array and checks whether the
+   * array is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
    */
-  inline size_t size_in_bytes() const noexcept;
-
+  simdjson_inline simdjson_result<bool> is_empty() & noexcept;
   /**
-   * After iterating through the stream, this method
-   * returns the number of bytes that were not parsed at the end
-   * of the stream. If truncated_bytes() differs from zero,
-   * then the input was truncated maybe because incomplete JSON
-   * documents were found at the end of the stream. You
-   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the array. You should still consume values only once even if you
+   * can iterate through the array more than once. If you unescape a string
+   * within the array more than once, you have unsafe code. Note that rewinding
+   * an array means that you may need to reparse it anew: it is not a free
+   * operation.
    *
-   * You should only call truncated_bytes() after streaming through all
-   * documents, like so:
+   * @returns true if the array contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
    *
-   *   document_stream stream = parser.iterate_many(json,window);
-   *   for(auto & doc : stream) {
-   *      // do something with doc
-   *   }
-   *   size_t truncated = stream.truncated_bytes();
+   *   ondemand::parser parser;
+   *   auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/0/foo/a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an array
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may only call at_pointer on an array after it has been created, but before it has
+   * been first accessed. When calling at_pointer on an array, the pointer is advanced to
+   * the location indicated by the JSON pointer (in case of success). It is no longer possible
+   * to call at_pointer on the same array.
    *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
    */
-  inline size_t truncated_bytes() const noexcept;
-
-  class iterator {
-  public:
-    using value_type = simdjson_result<document>;
-    using reference  = simdjson_result<ondemand::document_reference>;
-    using pointer    = void;
-    using difference_type   = std::ptrdiff_t;
-    using iterator_category = std::input_iterator_tag;
-
-    /**
-     * Default constructor.
-     */
-    simdjson_inline iterator() noexcept;
-    /**
-     * Get the current document (or error).
-     */
-    simdjson_inline reference operator*() noexcept;
-    /**
-     * Advance to the next document (prefix).
-     */
-    inline iterator& operator++() noexcept;
-    /**
-     * Check if we're at the end yet.
-     * @param other the end iterator to compare to.
-     */
-    simdjson_inline bool operator!=(const iterator &other) const noexcept;
-    /**
-     * @private
-     *
-     * Gives the current index in the input document in bytes.
-     *
-     *   document_stream stream = parser.parse_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      auto doc = *i;
-     *      size_t index = i.current_index();
-     *   }
-     *
-     * This function (current_index()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     */
-     simdjson_inline size_t current_index() const noexcept;
-
-     /**
-     * @private
-     *
-     * Gives a view of the current document at the current position.
-     *
-     *   document_stream stream = parser.iterate_many(json,window);
-     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
-     *      std::string_view v = i.source();
-     *   }
-     *
-     * The returned string_view instance is simply a map to the (unparsed)
-     * source string: it may thus include white-space characters and all manner
-     * of padding.
-     *
-     * This function (source()) is experimental and the usage
-     * may change in future versions of simdjson: we find the API somewhat
-     * awkward and we would like to offer something friendlier.
-     *
-     */
-     simdjson_inline std::string_view source() const noexcept;
-
-    /**
-     * Returns error of the stream (if any).
-     */
-     inline error_code error() const noexcept;
-
-  private:
-    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
-    /** The document_stream we're iterating through. */
-    document_stream* stream;
-    /** Whether we're finished or not. */
-    bool finished;
-
-    friend class document;
-    friend class document_stream;
-    friend class json_iterator;
-  };
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
-   * Start iterating the documents in the stream.
-   */
-  simdjson_inline iterator begin() noexcept;
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+  */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+
   /**
-   * The end of the stream, for iterator comparison purposes.
+   * Consumes the array and returns a string_view instance corresponding to the
+   * array as represented in JSON. It points inside the original document.
    */
-  simdjson_inline iterator end() noexcept;
-
-private:
-
-  document_stream &operator=(const document_stream &) = delete; // Disallow copying
-  document_stream(const document_stream &other) = delete; // Disallow copying
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
   /**
-   * Construct a document_stream. Does not allocate or parse anything until the iterator is
-   * used.
+   * Get the value at the given index. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * @param parser is a reference to the parser instance used to generate this document_stream
-   * @param buf is the raw byte buffer we need to process
-   * @param len is the length of the raw byte buffer in bytes
-   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline document_stream(
-    ondemand::parser &parser,
-    const uint8_t *buf,
-    size_t len,
-    size_t batch_size,
-    bool allow_comma_separated
-  ) noexcept;
-
+  simdjson_inline simdjson_result<value> at(size_t index) noexcept;
+protected:
   /**
-   * Parse the first document in the buffer. Used by begin(), to handle allocation and
-   * initialization.
+   * Go to the end of the array, no matter where you are right now.
    */
-  inline void start() noexcept;
+  simdjson_inline error_code consume() noexcept;
 
   /**
-   * Parse the next document found in the buffer previously given to document_stream.
+   * Begin array iteration.
    *
-   * The content should be a valid JSON document encoded as UTF-8. If there is a
-   * UTF-8 BOM, the parser skips it.
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   */
+  static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
+  /**
+   * Begin array iteration from the root.
    *
-   * You do NOT need to pre-allocate a parser.  This function takes care of
-   * pre-allocating a capacity defined by the batch_size defined when creating the
-   * document_stream object.
+   * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
+   *        resulting array.
+   * @error INCORRECT_TYPE if the iterator is not at [.
+   * @error TAPE_ERROR if there is no closing ] at the end of the document.
+   */
+  static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
+  /**
+   * Begin array iteration.
    *
-   * The function returns simdjson::EMPTY if there is no more data to be parsed.
+   * This version of the method should be called after the initial [ has been verified, and is
+   * intended for use by switch statements that check the type of a value.
    *
-   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
-   * and indicates that the buffer has successfully been parsed to the end.
-   * Every document it contained has been parsed without error.
+   * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
+   */
+  static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
+
+  /**
+   * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
    *
-   * The function returns an error code from simdjson/simdjson.h in case of failure
-   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
-   * the simdjson::error_message function converts these error codes into a string).
+   * @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
+   *        == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
+   *        into the resulting array.
+   */
+  simdjson_inline array(const value_iterator &iter) noexcept;
+
+  /**
+   * Iterator marking current position.
    *
-   * You can also check validity by calling parser.is_valid(). The same parser can
-   * and should be reused for the other documents in the buffer.
+   * iter.is_alive() == false indicates iteration is complete.
    */
-  inline void next() noexcept;
+  value_iterator iter{};
 
-  /** Move the json_iterator of the document to the location of the next document in the stream. */
-  inline void next_document() noexcept;
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<value>;
+  friend struct simdjson_result<array>;
+  friend class array_iterator;
+};
 
-  /** Get the next document index. */
-  inline size_t next_batch_start() const noexcept;
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-  /** Pass the next batch through stage 1 with the given parser. */
-  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
+namespace simdjson {
 
-  // Fields
-  ondemand::parser *parser;
-  const uint8_t *buf;
-  size_t len;
-  size_t batch_size;
-  bool allow_comma_separated;
-  /**
-   * We are going to use just one document instance. The document owns
-   * the json_iterator. It implies that we only ever pass a reference
-   * to the document to the users.
-   */
-  document doc{};
-  /** The error (or lack thereof) from the current document. */
-  error_code error;
-  size_t batch_start{0};
-  size_t doc_index{};
+template<>
+struct simdjson_result<lasx::ondemand::array> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::array &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() noexcept;
+  inline simdjson_result<size_t> count_elements() & noexcept;
+  inline simdjson_result<bool> is_empty() & noexcept;
+  inline simdjson_result<bool> reset() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+
+};
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H
+/* end file simdjson/generic/ondemand/array.h for lasx */
+/* including simdjson/generic/ondemand/array_iterator.h for lasx: #include "simdjson/generic/ondemand/array_iterator.h" */
+/* begin file simdjson/generic/ondemand/array_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
-  bool use_thread;
 
-  inline void load_from_stage1_thread() noexcept;
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-  /** Start a thread to run stage 1 on the next batch. */
-  inline void start_stage1_thread() noexcept;
+/**
+ * A forward-only JSON array.
+ *
+ * This is an input_iterator, meaning:
+ * - It is forward-only
+ * - * must be called exactly once per element.
+ * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
+ */
+class array_iterator {
+public:
+  /** Create a new, invalid array iterator. */
+  simdjson_inline array_iterator() noexcept = default;
 
-  /** Wait for the stage 1 thread to finish and capture the results. */
-  inline void finish_stage1_thread() noexcept;
+  //
+  // Iterator interface
+  //
 
-  /** The error returned from the stage 1 thread. */
-  error_code stage1_thread_error{UNINITIALIZED};
-  /** The thread used to run stage 1 against the next batch in the background. */
-  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
   /**
-   * The parser used to run stage 1 in the background. Will be swapped
-   * with the regular parser when finished.
+   * Get the current element.
+   *
+   * Part of the std::iterator interface.
    */
-  ondemand::parser stage1_thread_parser{};
+  simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  /**
+   * Check if we are at the end of the JSON.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are no more elements in the JSON array.
+   */
+  simdjson_inline bool operator==(const array_iterator &) const noexcept;
+  /**
+   * Check if there are more elements in the JSON array.
+   *
+   * Part of the std::iterator interface.
+   *
+   * @return true if there are more elements in the JSON array.
+   */
+  simdjson_inline bool operator!=(const array_iterator &) const noexcept;
+  /**
+   * Move to the next element.
+   *
+   * Part of the std::iterator interface.
+   */
+  simdjson_inline array_iterator &operator++() noexcept;
 
-  friend struct stage1_worker;
-  #endif // SIMDJSON_THREADS_ENABLED
+private:
+  value_iterator iter{};
 
-  friend class parser;
-  friend class document;
-  friend class json_iterator;
-  friend struct simdjson_result<ondemand::document_stream>;
-  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
-};  // document_stream
+  simdjson_inline array_iterator(const value_iterator &iter) noexcept;
+
+  friend class array;
+  friend class value;
+  friend struct simdjson_result<array_iterator>;
+};
 
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
 namespace simdjson {
+
 template<>
-struct simdjson_result<lasx::ondemand::document_stream> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_stream> {
+struct simdjson_result<lasx::ondemand::array_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::document_stream &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::array_iterator &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+
+  //
+  // Iterator interface
+  //
+
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::array_iterator> &) const noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &operator++() noexcept;
 };
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
-/* end file simdjson/generic/ondemand/document_stream.h for lasx */
-/* including simdjson/generic/ondemand/field.h for lasx: #include "simdjson/generic/ondemand/field.h" */
-/* begin file simdjson/generic/ondemand/field.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H
+/* end file simdjson/generic/ondemand/array_iterator.h for lasx */
+/* including simdjson/generic/ondemand/document.h for lasx: #include "simdjson/generic/ondemand/document.h" */
+/* begin file simdjson/generic/ondemand/document.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
+
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
 /**
- * A JSON field (key/value pair) in an object.
+ * A JSON document. It holds a json_iterator instance.
  *
- * Returned from object iteration.
+ * Used by tokens to get text, and string buffer location.
  *
- * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
+ * You must keep the document around during iteration.
  */
-class field : public std::pair<raw_json_string, value> {
+class document {
 public:
   /**
-   * Create a new invalid field.
+   * Create a new invalid document.
    *
    * Exists so you can declare a variable and later assign to it before use.
    */
-  simdjson_inline field() noexcept;
+  simdjson_inline document() noexcept = default;
+  simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
+  simdjson_inline document(document &&other) noexcept = default;
+  simdjson_inline document &operator=(const document &other) noexcept = delete;
+  simdjson_inline document &operator=(document &&other) noexcept = default;
 
   /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it.
+   * Cast this JSON value to an array.
    *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
+   * @returns An object that can be used to iterate the array.
+   * @returns INCORRECT_TYPE If the JSON value is not an array.
    */
-  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
   /**
-   * Get the key as a string_view (for higher speed, consider raw_key).
-   * We deliberately use a more cumbersome name (unescaped_key) to force users
-   * to think twice about using it. The content is stored in the receiver.
+   * Cast this JSON value to an object.
    *
-   * This consumes the key: once you have called unescaped_key(), you cannot
-   * call it again nor can you call key().
+   * @returns An object that can be used to look up or iterate fields.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
    */
-  template <typename string_type>
-  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
   /**
-   * Get the key as a raw_json_string. Can be used for direct comparison with
-   * an unescaped C string: e.g., key() == "test". This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key() for a similar function which returns
-   * a more convenient std::string_view result.
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline raw_json_string key() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
   /**
-   * Get the unprocessed key as a string_view. This includes the quotes and may include
-   * some spaces after the last quote. This does not count as
-   * consumption of the content: you can safely call it repeatedly.
-   * See escaped_key().
+   * Cast this JSON value (inside string) to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
    */
-  simdjson_inline std::string_view key_raw_json_token() const noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
   /**
-   * Get the key as a string_view. This does not include the quotes and
-   * the string is unprocessed key so it may contain escape characters
-   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
-   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline std::string_view escaped_key() const noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
   /**
-   * Get the field value.
+   * Cast this JSON value (inside string) to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
    */
-  simdjson_inline ondemand::value &value() & noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
   /**
-   * @overload ondemand::value &ondemand::value() & noexcept
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
    */
-  simdjson_inline ondemand::value value() && noexcept;
-
-protected:
-  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
-  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
-  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
-  friend struct simdjson_result<field>;
-  friend class object_iterator;
-};
-
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
-
-template<>
-struct simdjson_result<lasx::ondemand::field> : public lasx::implementation_simdjson_result_base<lasx::ondemand::field> {
-public:
-  simdjson_inline simdjson_result(lasx::ondemand::field &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
 
-  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
-  template<typename string_type>
-  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> key() noexcept;
-  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
-  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> value() noexcept;
-};
+  /**
+   * Cast this JSON value (inside string) to a double.
+   *
+   * @returns A double.
+   * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: Calling get_string() twice on the same document is an error.
+   *
+   * @param Whether to allow a replacement character for unmatched surrogate pairs.
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  /**
+   * Attempts to fill the provided std::string reference with the parsed value of the current string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * Important: a value should be consumed once. Calling get_string() twice on the same value
+   * is an error.
+   *
+   * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
+   * We recommend you avoid allocating an std::string unless you need to.
+   *
+   * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
+   */
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+   *
+   * Important: Calling get_wobbly_string() twice on the same document is an error.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @returns INCORRECT_TYPE if the JSON value is not a string.
+   */
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @returns INCORRECT_TYPE if the JSON value is not true or false.
+   */
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
+   * by default), and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value if a JSON array or object cannot be found.
+   * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline simdjson_result<value> get_value() noexcept;
 
-} // namespace simdjson
+  /**
+   * Checks if this JSON value is null.  If and only if the value is
+   * null, then it is consumed (we advance). If we find a token that
+   * begins with 'n' but is not 'null', then an error is returned.
+   *
+   * @returns Whether the value is null.
+   * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
+   */
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
-/* end file simdjson/generic/ondemand/field.h for lasx */
-/* including simdjson/generic/ondemand/object.h for lasx: #include "simdjson/generic/ondemand/object.h" */
-/* begin file simdjson/generic/ondemand/object.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
+   *
+   * You may use get_double(), get_bool(), get_uint64(), get_int64(),
+   * get_object(), get_array(), get_raw_json_string(), or get_string() instead.
+   *
+   * @returns A value of the given type, parsed from the JSON.
+   * @returns INCORRECT_TYPE If the JSON value is not the given type.
+   */
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  /**
+   * @overload template<typename T> simdjson_result<T> get() & noexcept
+   *
+   * We disallow the use tag_invoke CPO on a moved document; it may create UB
+   * if user uses `ondemand::array` or `ondemand::object` in their custom type.
+   *
+   * The member function is still remains specialize-able for compatibility
+   * reasons, but we completely disallow its use when a tag_invoke customization
+   * is provided.
+   */
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  /**
+   * Get this value as the given type.
+   *
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
+   */
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+#if SIMDJSON_EXCEPTIONS
+  /**
+   * Cast this JSON value to an instance of type T. The programmer is responsible for
+   * providing an implementation of get<T> for the type T, if T is not one of the types
+   * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.)
+   *
+   * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types
+   *
+   * @returns An instance of type T
+   */
+  template <class T>
+  explicit simdjson_inline operator T() & noexcept(false);
+  template <class T>
+  explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
 
-/**
- * A forward-only JSON object field iterator.
- */
-class object {
-public:
   /**
-   * Create a new invalid object.
+   * Cast this JSON value to an array.
+   *
+   * @returns An object that can be used to iterate the array.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
+   */
+  simdjson_inline operator array() & noexcept(false);
+  /**
+   * Cast this JSON value to an object.
+   *
+   * @returns An object that can be used to look up or iterate fields.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
+   */
+  simdjson_inline operator object() & noexcept(false);
+  /**
+   * Cast this JSON value to an unsigned integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
+   */
+  simdjson_inline operator uint64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a signed integer.
+   *
+   * @returns A signed 64-bit integer.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
+   */
+  simdjson_inline operator int64_t() noexcept(false);
+  /**
+   * Cast this JSON value to a double.
+   *
+   * @returns A double.
+   * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
+   */
+  simdjson_inline operator double() noexcept(false);
+  /**
+   * Cast this JSON value to a string.
+   *
+   * The string is guaranteed to be valid UTF-8.
+   *
+   * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
+   *          time it parses a document or when it is destroyed.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator std::string_view() noexcept(false);
+  /**
+   * Cast this JSON value to a raw_json_string.
+   *
+   * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
+   *
+   * @returns A pointer to the raw JSON for the given string.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
+   */
+  simdjson_inline operator raw_json_string() noexcept(false);
+  /**
+   * Cast this JSON value to a bool.
+   *
+   * @returns A bool value.
+   * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
+   */
+  simdjson_inline operator bool() noexcept(false);
+  /**
+   * Cast this JSON value to a value when the document is an object or an array.
+   *
+   * You must not have begun iterating through the object or array. When
+   * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
+   * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
+   * rewind() to reset the document to its initial state before calling this method.
+   *
+   * @returns A value value if a JSON array or object cannot be found.
+   * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
+   */
+  simdjson_inline operator value() noexcept(false);
+#endif
+  /**
+   * This method scans the array and counts the number of elements.
+   * The count_elements method should always be called before you have begun
+   * iterating through the array: it is expected that you are pointing at
+   * the beginning of the array.
+   * The runtime complexity is linear in the size of the array. After
+   * calling this function, if successful, the array is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue. Note that count_elements() does not validate the JSON values,
+   * only the structure of the array.
+   */
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+   /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Get the value at the given index in the array. This function has linear-time complexity.
+   * This function should only be called once on an array instance since the array iterator is not reset between each call.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * @return The value at the given index, or:
+   *         - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
    */
-  simdjson_inline object() noexcept = default;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  /**
+   * Begin array iteration.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  /**
+   * Sentinel representing the end of the array.
+   *
+   * Part of the std::iterable interface.
+   */
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
 
-  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<object_iterator> end() noexcept;
   /**
    * Look up a field by name on an object (order-sensitive).
    *
@@ -122968,32 +115552,28 @@ class object {
    * double y = obj.find_field("y");
    * double x = obj.find_field("x");
    * ```
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
    *
    * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
    * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
    *
+   *
    * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * invalidates previous field values: it makes them unsafe. E.g., the array
    * given by content["bids"].get_array() should not be accessed after you have called
    * content["asks"].get_array(). You can detect such mistakes by first compiling and running
    * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
    * OUT_OF_ORDER_ITERATION error is generated.
    *
-   * You are expected to access keys only once. You should access the value corresponding to a
-   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * You are expected to access keys only once. You should access the value corresponding to
+   * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
    * is an error.
    *
-   * If you expect to have keys with escape characters, please review our documentation.
-   *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
   simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
 
   /**
    * Look up a field by name on an object, without regard to key order.
@@ -123011,37 +115591,195 @@ class object {
    * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
    * field was not there when they are not in order).
    *
-   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
-   * that only one field is returned.
-   *
    * You must consume the fields on an object one at a time. A request for a new key
-   * invalidates previous field values: it makes them unsafe. The value instance you get
-   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * invalidates previous field values: it makes them unsafe. E.g., the array
    * given by content["bids"].get_array() should not be accessed after you have called
    * content["asks"].get_array(). You can detect such mistakes by first compiling and running
    * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
    * OUT_OF_ORDER_ITERATION error is generated.
    *
    * You are expected to access keys only once. You should access the value corresponding to a key
-   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
-   *
-   * If you expect to have keys with escape characters, please review our documentation.
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
    *
    * @param key The key to look up.
    * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
    */
   simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
   simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
   /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
-  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+ simdjson_result<value> operator[](int) & noexcept = delete;
 
   /**
-   * Get the value associated with the given JSON pointer. We use the RFC 6901
-   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
-   * as the root of its own JSON document.
+   * Get the type of this JSON value. It does not validate or consume the value.
+   * E.g., you must still call "is_null()" to check that a value is null even if
+   * "type()" returns json_type::null.
+   *
+   * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
+   * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
+   * let it throw an exception).
+   *
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+
+  /**
+   * Checks whether the document is a scalar (string, number, null, Boolean).
+   * Returns false when there it is an array or object.
+   *
+   * @returns true if the type is string, number, null, Boolean
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+
+  /**
+   * Checks whether the document is a string.
+   *
+   * @returns true if the type is string
+   * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
+   */
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+
+  /**
+   * Checks whether the document is a negative number.
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline bool is_negative() noexcept;
+  /**
+   * Checks whether the document is an integer number. Note that
+   * this requires to partially parse the number string. If
+   * the value is determined to be an integer, it may still
+   * not parse properly as an integer in subsequent steps
+   * (e.g., it might overflow).
+   *
+   * @returns true if the number if negative.
+   */
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  /**
+   * Determine the number type (integer or floating-point number) as quickly
+   * as possible. This function does not fully validate the input. It is
+   * useful when you only need to classify the numbers, without parsing them.
+   *
+   * If you are planning to retrieve the value or you need full validation,
+   * consider using the get_number() method instead: it will fully parse
+   * and validate the input, and give you access to the type:
+   * get_number().get_number_type().
+   *
+   * get_number_type() is number_type::unsigned_integer if we have
+   * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615.
+   * get_number_type() is number_type::signed_integer if we have an
+   * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808.
+   * get_number_type() is number_type::big_integer if we have an integer outside
+   * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808).
+   * Otherwise, get_number_type() has value number_type::floating_point_number
+   *
+   * This function requires processing the number string, but it is expected
+   * to be faster than get_number().get_number_type() because it is does not
+   * parse the number value.
+   *
+   * @returns the type of the number
+   */
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+
+  /**
+   * Attempt to parse an ondemand::number. An ondemand::number may
+   * contain an integer value or a floating-point value, the simdjson
+   * library will autodetect the type. Thus it is a dynamically typed
+   * number. Before accessing the value, you must determine the detected
+   * type.
+   *
+   * number.get_number_type() is number_type::signed_integer if we have
+   * an integer in [-9223372036854775808,9223372036854775808)
+   * You can recover the value by calling number.get_int64() and you
+   * have that number.is_int64() is true.
+   *
+   * number.get_number_type() is number_type::unsigned_integer if we have
+   * an integer in [9223372036854775808,18446744073709551616)
+   * You can recover the value by calling number.get_uint64() and you
+   * have that number.is_uint64() is true.
+   *
+   * Otherwise, number.get_number_type() has value number_type::floating_point_number
+   * and we have a binary64 number.
+   * You can recover the value by calling number.get_double() and you
+   * have that number.is_double() is true.
+   *
+   * You must check the type before accessing the value: it is an error
+   * to call "get_int64()" when number.get_number_type() is not
+   * number_type::signed_integer and when number.is_int64() is false.
+   */
+  simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
+
+  /**
+   * Get the raw JSON for this token.
+   *
+   * The string_view will always point into the input buffer.
+   *
+   * The string_view will start at the beginning of the token, and include the entire token
+   * *as well as all spaces until the next token (or EOF).* This means, for example, that a
+   * string token always begins with a " and is always terminated by the final ", possibly
+   * followed by a number of spaces.
+   *
+   * The string_view is *not* null-terminated. If this is a scalar (string, number,
+   * boolean, or null), the character after the end of the string_view may be the padded buffer.
+   *
+   * Tokens include:
+   * - {
+   * - [
+   * - "a string (possibly with UTF-8 or backslashed characters like \\\")".
+   * - -1.2e-100
+   * - true
+   * - false
+   * - null
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  /**
+   * Reset the iterator inside the document instance so we are pointing back at the
+   * beginning of the document, as if it had just been created. It invalidates all
+   * values, objects and arrays that you have created so far (including unescaped strings).
+   */
+  inline void rewind() noexcept;
+  /**
+   * Returns debugging information.
+   */
+  inline std::string to_debug_string() noexcept;
+  /**
+   * Some unrecoverable error conditions may render the document instance unusable.
+   * The is_alive() method returns true when the document is still suitable.
+   */
+  inline bool is_alive() noexcept;
+
+  /**
+   * Returns the current location in the document if in bounds.
+   */
+  inline simdjson_result<const char *> current_location() const noexcept;
+
+  /**
+   * Returns true if this document has been fully parsed.
+   * If you have consumed the whole document and at_end() returns
+   * false, then there may be trailing content.
+   */
+  inline bool at_end() const noexcept;
+
+  /**
+   * Returns the current depth in the document if in bounds.
+   *
+   * E.g.,
+   *  0 = finished with document
+   *  1 = document root value (could be [ or {, not yet known)
+   *  2 = , or } inside root array/object
+   *  3 = key or value inside root array/object.
+   */
+  simdjson_inline int32_t current_depth() const noexcept;
+
+  /**
+   * Get the value associated with the given JSON pointer.  We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard.
    *
    *   ondemand::parser parser;
    *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
@@ -123055,190 +115793,233 @@ class object {
    *   auto doc = parser.iterate(json);
    *   doc.at_pointer("//a/1") == 20
    *
-   * Note that at_pointer() called on the document automatically calls the document's rewind
-   * method between each call. It invalidates all previously accessed arrays, objects and values
-   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
-   * instance: there is no rewind and no invalidation.
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
    *
-   * You may call at_pointer more than once on an object, but each time the pointer is advanced
-   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
-   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/\\u00E9") == 123
+   *   doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD)
    *
-   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   * Note that at_pointer() automatically calls rewind between each call. Thus
+   * all values, objects and arrays that you have created so far (including unescaped strings)
+   * are invalidated. After calling at_pointer, you need to consume the result: string values
+   * should be stored in your own variables, arrays should be decoded and stored in your own array-like
+   * structures and so forth.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
    *
    * @return The value associated with the given JSON pointer, or:
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   *         - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
    */
-  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
   /**
    * Get the value associated with the given JSONPath expression. We only support
    * JSONPath queries that trivially convertible to JSON Pointer queries: key
    * names and array indices.
    *
+   * https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
+   *
+   * Key values are matched exactly, without unescaping or Unicode normalization.
+   * We do a byte-by-byte comparison. E.g.
+   *
+   *   const padded_string json = "{\"\\u00E9\":123}"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_path(".\\u00E9") == 123
+   *   doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD)
+   *
    * @return The value associated with the given JSONPath expression, or:
    *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
    *         - NO_SUCH_FIELD if a field does not exist in an object
    *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
    *         - INCORRECT_TYPE if a non-integer is used to access an array
    */
-  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
   /**
-   * Reset the iterator so that we are pointing back at the
-   * beginning of the object. You should still consume values only once even if you
-   * can iterate through the object more than once. If you unescape a string or a key
-   * within the object more than once, you have unsafe code. Note that rewinding an object
-   * means that you may need to reparse it anew: it is not a free operation.
-   *
-   * @returns true if the object contains some elements (not empty)
-   */
-  inline simdjson_result<bool> reset() & noexcept;
-  /**
-   * This method scans the beginning of the object and checks whether the
-   * object is empty.
-   * The runtime complexity is constant time. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   */
-  inline simdjson_result<bool> is_empty() & noexcept;
-  /**
-   * This method scans the object and counts the number of key-value pairs.
-   * The count_fields method should always be called before you have begun
-   * iterating through the object: it is expected that you are pointing at
-   * the beginning of the object.
-   * The runtime complexity is linear in the size of the object. After
-   * calling this function, if successful, the object is 'rewinded' at its
-   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
-   * there is a missing comma), then an error is returned and it is no longer
-   * safe to continue.
-   *
-   * To check that an object is empty, it is more performant to use
-   * the is_empty() method.
-   *
-   * Performance hint: You should only call count_fields() as a last
-   * resort as it may require scanning the document twice or more.
-   */
-  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
-  /**
-   * Consumes the object and returns a string_view instance corresponding to the
-   * object as represented in JSON. It points inside the original byte array containing
+   * Consumes the document and returns a string_view instance corresponding to the
+   * document as represented in JSON. It points inside the original byte array containing
    * the JSON document.
    */
   simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
-
 protected:
   /**
-   * Go to the end of the object, no matter where you are right now.
+   * Consumes the document.
    */
   simdjson_inline error_code consume() noexcept;
-  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
-  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
-  static simdjson_inline object resume(const value_iterator &iter) noexcept;
-  simdjson_inline object(const value_iterator &iter) noexcept;
 
-  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
+  simdjson_inline document(ondemand::json_iterator &&iter) noexcept;
+  simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
 
-  value_iterator iter{};
+  simdjson_inline value_iterator resume_value_iterator() noexcept;
+  simdjson_inline value_iterator get_root_value_iterator() noexcept;
+  simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
+  static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept;
+
+  //
+  // Fields
+  //
+  json_iterator iter{}; ///< Current position in the document
+  static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
 
+  friend class array_iterator;
   friend class value;
-  friend class document;
-  friend struct simdjson_result<object>;
+  friend class ondemand::parser;
+  friend class object;
+  friend class array;
+  friend class field;
+  friend class token;
+  friend class document_stream;
+  friend class document_reference;
 };
 
-} // namespace ondemand
-} // namespace lasx
-} // namespace simdjson
-
-namespace simdjson {
 
-template<>
-struct simdjson_result<lasx::ondemand::object> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object> {
+/**
+ * A document_reference is a thin wrapper around a document reference instance.
+ * The document_reference instances are used primarily/solely for streams of JSON
+ * documents. They differ from document instances when parsing a scalar value
+ * (a document that is not an array or an object). In the case of a document,
+ * we expect the document to be fully consumed. In the case of a document_reference,
+ * we allow trailing content.
+ */
+class document_reference {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::object &&value) noexcept; ///< @private
-  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
-  simdjson_inline simdjson_result() noexcept = default;
-
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> begin() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> end() noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) && noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
-  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
-
-  inline simdjson_result<bool> reset() noexcept;
-  inline simdjson_result<bool> is_empty() noexcept;
-  inline simdjson_result<size_t> count_fields() & noexcept;
-  inline simdjson_result<std::string_view> raw_json() noexcept;
-
-};
-
-} // namespace simdjson
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
-/* end file simdjson/generic/ondemand/object.h for lasx */
-/* including simdjson/generic/ondemand/object_iterator.h for lasx: #include "simdjson/generic/ondemand/object_iterator.h" */
-/* begin file simdjson/generic/ondemand/object_iterator.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+  simdjson_inline document_reference() noexcept;
+  simdjson_inline document_reference(document &d) noexcept;
+  simdjson_inline document_reference(const document_reference &other) noexcept = default;
+  simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
+  simdjson_inline void rewind() noexcept;
+  simdjson_inline simdjson_result<array> get_array() & noexcept;
+  simdjson_inline simdjson_result<object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<value> get_value() noexcept;
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+  template <typename T>
+  simdjson_inline simdjson_result<T> get() &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+    static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
+    T out{};
+    SIMDJSON_TRY(get<T>(out));
+    return out;
+  }
+  template<typename T>
+  simdjson_inline simdjson_result<T> get() &&
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
+#else
+    noexcept
+#endif
+  {
+      static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour.");
+      return static_cast<document&>(*this).get<T>();
+  }
 
-class object_iterator {
-public:
   /**
-   * Create a new invalid object_iterator.
+   * Get this value as the given type.
    *
-   * Exists so you can declare a variable and later assign to it before use.
+   * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
+   *
+   * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
+   *
+   * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
+   * @returns INCORRECT_TYPE If the JSON value is not an object.
+   * @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
    */
-  simdjson_inline object_iterator() noexcept = default;
-
-  //
-  // Iterator interface
-  //
+  template<typename T>
+  simdjson_inline error_code get(T &out) &
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document_reference> : true)
+#else
+    noexcept
+#endif
+  {
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    if constexpr (custom_deserializable<T, document_reference>) {
+        return deserialize(*this, out);
+    } else {
+#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
+      // Unless the simdjson library or the user provides an inline implementation, calling this method should
+      // immediately fail.
+      static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
+        "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
+        "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
+        " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
+        " You may also add support for custom types, see our documentation.");
+      static_cast<void>(out); // to get rid of unused errors
+      return UNINITIALIZED;
+#if SIMDJSON_SUPPORTS_DESERIALIZATION
+    }
+#endif
+  }
+  /** @overload template<typename T> error_code get(T &out) & noexcept */
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
+  simdjson_inline operator document&() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator array() & noexcept(false);
+  simdjson_inline operator object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
+  simdjson_result<value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
 
-  // Reads key and value, yielding them to the user.
-  // MUST ONLY BE CALLED ONCE PER ITERATION.
-  simdjson_inline simdjson_result<field> operator*() noexcept;
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const object_iterator &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline object_iterator &operator++() noexcept;
+  simdjson_inline simdjson_result<json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
 
-private:
-  /**
-   * The underlying JSON iterator.
-   *
-   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
-   * is first used, and never changes afterwards.
-   */
-  value_iterator iter{};
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<number> get_number() noexcept;
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+  simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
-  friend struct simdjson_result<object_iterator>;
-  friend class object;
+private:
+  document *doc{nullptr};
 };
-
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
@@ -123246,588 +116027,588 @@ class object_iterator {
 namespace simdjson {
 
 template<>
-struct simdjson_result<lasx::ondemand::object_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object_iterator> {
+struct simdjson_result<lasx::ondemand::document> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document> {
 public:
-  simdjson_inline simdjson_result(lasx::ondemand::object_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(lasx::ondemand::document &&value) noexcept; ///< @private
   simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
   simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
 
-  //
-  // Iterator interface
-  //
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
 
-  // Reads key and value, yielding them to the user.
-  simdjson_inline simdjson_result<lasx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
-  // Assumes it's being compared with the end. true if depth < iter->depth.
-  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
-  // Assumes it's being compared with the end. true if depth >= iter->depth.
-  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
-  // Checks for ']' and ','
-  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &operator++() noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
+#if SIMDJSON_EXCEPTIONS
+  template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lasx::ondemand::value() noexcept(false);
+#endif
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline int32_t current_depth() const noexcept;
+  simdjson_inline bool at_end() const noexcept;
+  simdjson_inline bool is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
+
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
 };
 
+
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
-/* end file simdjson/generic/ondemand/object_iterator.h for lasx */
-/* including simdjson/generic/ondemand/serialization.h for lasx: #include "simdjson/generic/ondemand/serialization.h" */
-/* begin file simdjson/generic/ondemand/serialization.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-/**
- * Create a string-view instance out of a document instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept;
-/**
- * Create a string-view instance out of a value instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. The value must
- * not have been accessed previously. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept;
-/**
- * Create a string-view instance out of an object instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept;
-/**
- * Create a string-view instance out of an array instance. The string-view instance
- * contains JSON text that is suitable to be parsed as JSON again. It does not
- * validate the content.
- */
-inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept;
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x);
-inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x);
-} // namespace simdjson
 
-/**
- * We want to support argument-dependent lookup (ADL).
- * Hence we should define operator<< in the namespace
- * where the argument (here value, object, etc.) resides.
- * Credit: @madhur4127
- * See https://github.com/simdjson/simdjson/issues/1768
- */
-namespace simdjson { namespace lasx { namespace ondemand {
+template<>
+struct simdjson_result<lasx::ondemand::document_reference> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_reference> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::document_reference value, error_code error) noexcept;
+  simdjson_inline simdjson_result() noexcept = default;
+  simdjson_inline error_code rewind() noexcept;
 
-/**
- * Print JSON to an output stream.  It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The element.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The array.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x);
-#endif
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value);
-#if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x);
-#endif
-/**
- * Print JSON to an output stream. It does not
- * validate the content.
- *
- * @param out The output stream.
- * @param value The object.
- * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
- */
-inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value);
+  simdjson_inline simdjson_result<lasx::ondemand::array> get_array() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object> get_object() & noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
+  simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
+  simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
+  simdjson_inline simdjson_result<double> get_double() noexcept;
+  simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
+  template <typename string_type>
+  simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> get_raw_json_string() noexcept;
+  simdjson_inline simdjson_result<bool> get_bool() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> get_value() noexcept;
+  simdjson_inline simdjson_result<bool> is_null() noexcept;
+
+  template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
+  template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
+
+  template<typename T> simdjson_inline error_code get(T &out) & noexcept;
+  template<typename T> simdjson_inline error_code get(T &out) && noexcept;
 #if SIMDJSON_EXCEPTIONS
-inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::object> x);
+  template <class T>
+  explicit simdjson_inline operator T() noexcept(false);
+  simdjson_inline operator lasx::ondemand::array() & noexcept(false);
+  simdjson_inline operator lasx::ondemand::object() & noexcept(false);
+  simdjson_inline operator uint64_t() noexcept(false);
+  simdjson_inline operator int64_t() noexcept(false);
+  simdjson_inline operator double() noexcept(false);
+  simdjson_inline operator std::string_view() noexcept(false);
+  simdjson_inline operator lasx::ondemand::raw_json_string() noexcept(false);
+  simdjson_inline operator bool() noexcept(false);
+  simdjson_inline operator lasx::ondemand::value() noexcept(false);
 #endif
-}}} // namespace simdjson::lasx::ondemand
+  simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at(size_t index) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> begin() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::array_iterator> end() & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](const char *key) & noexcept;
+  simdjson_result<lasx::ondemand::value> operator[](int) & noexcept = delete;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(const char *key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::json_type> type() noexcept;
+  simdjson_inline simdjson_result<bool> is_scalar() noexcept;
+  simdjson_inline simdjson_result<bool> is_string() noexcept;
+  simdjson_inline simdjson_result<const char *> current_location() noexcept;
+  simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
+  simdjson_inline simdjson_result<bool> is_negative() noexcept;
+  simdjson_inline simdjson_result<bool> is_integer() noexcept;
+  simdjson_inline simdjson_result<lasx::number_type> get_number_type() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::number> get_number() noexcept;
+  /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
+  simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
-/* end file simdjson/generic/ondemand/serialization.h for lasx */
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
+};
 
-// Deserialization for standard types
-/* including simdjson/generic/ondemand/std_deserialize.h for lasx: #include "simdjson/generic/ondemand/std_deserialize.h" */
-/* begin file simdjson/generic/ondemand/std_deserialize.h for lasx */
-#if SIMDJSON_SUPPORTS_DESERIALIZATION
 
-#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
+/* end file simdjson/generic/ondemand/document.h for lasx */
+/* including simdjson/generic/ondemand/document_stream.h for lasx: #include "simdjson/generic/ondemand/document_stream.h" */
+/* begin file simdjson/generic/ondemand/document_stream.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <concepts>
-#include <limits>
+#ifdef SIMDJSON_THREADS_ENABLED
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#endif
 
 namespace simdjson {
-template <typename T>
-constexpr bool require_custom_serialization = false;
-
-//////////////////////////////
-// Number deserialization
-//////////////////////////////
-
-template <std::unsigned_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
-
-  uint64_t x;
-  SIMDJSON_TRY(val.get_uint64().get(x));
-  if (x > (limits::max)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
-
-template <std::floating_point T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  double x;
-  SIMDJSON_TRY(val.get_double().get(x));
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
+namespace lasx {
+namespace ondemand {
 
-template <std::signed_integral T>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
-  using limits = std::numeric_limits<T>;
+#ifdef SIMDJSON_THREADS_ENABLED
+/** @private Custom worker class **/
+struct stage1_worker {
+  stage1_worker() noexcept = default;
+  stage1_worker(const stage1_worker&) = delete;
+  stage1_worker(stage1_worker&&) = delete;
+  stage1_worker operator=(const stage1_worker&) = delete;
+  ~stage1_worker();
+  /**
+   * We only start the thread when it is needed, not at object construction, this may throw.
+   * You should only call this once.
+   **/
+  void start_thread();
+  /**
+   * Start a stage 1 job. You should first call 'run', then 'finish'.
+   * You must call start_thread once before.
+   */
+  void run(document_stream * ds, parser * stage1, size_t next_batch_start);
+  /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/
+  void finish();
 
-  int64_t x;
-  SIMDJSON_TRY(val.get_int64().get(x));
-  if (x > (limits::max)() || x < (limits::min)()) {
-    return NUMBER_OUT_OF_RANGE;
-  }
-  out = static_cast<T>(x);
-  return SUCCESS;
-}
+private:
 
-/**
- * STL containers have several constructors including one that takes a single
- * size argument. Thus, some compilers (Visual Studio) will not be able to
- * disambiguate between the size and container constructor. Users should
- * explicitly specify the type of the container as needed: e.g.,
- * doc.get<std::vector<int>>().
- */
-template <concepts::appendable_containers T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the container must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the container must default constructible.");
+  /**
+   * Normally, we would never stop the thread. But we do in the destructor.
+   * This function is only safe assuming that you are not waiting for results. You
+   * should have called run, then finish, and be done.
+   **/
+  void stop_thread();
 
-  lasx::ondemand::array arr;
-  SIMDJSON_TRY(val.get_array().get(arr));
-  for (auto v : arr) {
-    if constexpr (concepts::returns_reference<T>) {
-      if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
-          err) {
-        // If an error occurs, the empty element that we just inserted gets
-        // removed. We're not using a temp variable because if T is a heavy
-        // type, we want the valid path to be the fast path and the slow path be
-        // the path that has errors in it.
-        if constexpr (requires { out.pop_back(); }) {
-          static_cast<void>(out.pop_back());
-        }
-        return err;
-      }
-    } else {
-      value_type temp;
-      if (auto const err = v.get<value_type>().get(temp); err) {
-        return err;
-      }
-      concepts::emplace_one(out, std::move(temp));
-    }
-  }
-  return SUCCESS;
-}
+  std::thread thread{};
+  /** These three variables define the work done by the thread. **/
+  ondemand::parser * stage1_thread_parser{};
+  size_t _next_batch_start{};
+  document_stream * owner{};
+  /**
+   * We have two state variables. This could be streamlined to one variable in the future but
+   * we use two for clarity.
+   */
+  bool has_work{false};
+  bool can_work{true};
 
+  /**
+   * We lock using a mutex.
+   */
+  std::mutex locking_mutex{};
+  std::condition_variable cond_var{};
 
+  friend class document_stream;
+};
+#endif  // SIMDJSON_THREADS_ENABLED
 
 /**
- * This CPO (Customization Point Object) will help deserialize into
- * smart pointers.
+ * A forward-only stream of documents.
  *
- * If constructing T is nothrow, this conversion should be nothrow as well since
- * we return MEMALLOC if we're not able to allocate memory instead of throwing
- * the error message.
+ * Produced by parser::iterate_many.
  *
- * @tparam T The type inside the smart pointer
- * @tparam ValT document/value type
- * @param val document/value
- * @param out a reference to the smart pointer
- * @return status of the conversion
  */
-template <concepts::smart_pointer T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
-  using element_type = typename std::remove_cvref_t<T>::element_type;
+class document_stream {
+public:
+  /**
+   * Construct an uninitialized document_stream.
+   *
+   *  ```c++
+   *  document_stream docs;
+   *  auto error = parser.iterate_many(json).get(docs);
+   *  ```
+   */
+  simdjson_inline document_stream() noexcept;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream(document_stream &&other) noexcept = default;
+  /** Move one document_stream to another. */
+  simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
 
-  // For better error messages, don't use these as constraints on
-  // the tag_invoke CPO.
-  static_assert(
-      deserializable<element_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<element_type>,
-      "The specified type inside the unique_ptr must default constructible.");
+  simdjson_inline ~document_stream() noexcept;
 
-  auto ptr = new (std::nothrow) element_type();
-  if (ptr == nullptr) {
-    return MEMALLOC;
-  }
-  SIMDJSON_TRY(val.template get<element_type>(*ptr));
-  out.reset(ptr);
-  return SUCCESS;
-}
+  /**
+   * Returns the input size in bytes.
+   */
+  inline size_t size_in_bytes() const noexcept;
 
-/**
- * This CPO (Customization Point Object) will help deserialize into optional types.
- */
-template <concepts::optional_type T, typename ValT>
-  requires(!require_custom_serialization<T>)
-error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, ValT>) {
-  using value_type = typename std::remove_cvref_t<T>::value_type;
+  /**
+   * After iterating through the stream, this method
+   * returns the number of bytes that were not parsed at the end
+   * of the stream. If truncated_bytes() differs from zero,
+   * then the input was truncated maybe because incomplete JSON
+   * documents were found at the end of the stream. You
+   * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()).
+   *
+   * You should only call truncated_bytes() after streaming through all
+   * documents, like so:
+   *
+   *   document_stream stream = parser.iterate_many(json,window);
+   *   for(auto & doc : stream) {
+   *      // do something with doc
+   *   }
+   *   size_t truncated = stream.truncated_bytes();
+   *
+   */
+  inline size_t truncated_bytes() const noexcept;
 
-  static_assert(
-      deserializable<value_type, ValT>,
-      "The specified type inside the unique_ptr must itself be deserializable");
-  static_assert(
-      std::is_default_constructible_v<value_type>,
-      "The specified type inside the unique_ptr must default constructible.");
+  class iterator {
+  public:
+    using value_type = simdjson_result<document>;
+    using reference  = simdjson_result<ondemand::document_reference>;
+    using pointer    = void;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::input_iterator_tag;
 
-  if (!out) {
-    out.emplace();
-  }
-  SIMDJSON_TRY(val.template get<value_type>(out.value()));
-  return SUCCESS;
-}
+    /**
+     * Default constructor.
+     */
+    simdjson_inline iterator() noexcept;
+    /**
+     * Get the current document (or error).
+     */
+    simdjson_inline reference operator*() noexcept;
+    /**
+     * Advance to the next document (prefix).
+     */
+    inline iterator& operator++() noexcept;
+    /**
+     * Check if we're at the end yet.
+     * @param other the end iterator to compare to.
+     */
+    simdjson_inline bool operator!=(const iterator &other) const noexcept;
+    /**
+     * @private
+     *
+     * Gives the current index in the input document in bytes.
+     *
+     *   document_stream stream = parser.parse_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      auto doc = *i;
+     *      size_t index = i.current_index();
+     *   }
+     *
+     * This function (current_index()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     */
+     simdjson_inline size_t current_index() const noexcept;
 
-} // namespace simdjson
+     /**
+     * @private
+     *
+     * Gives a view of the current document at the current position.
+     *
+     *   document_stream stream = parser.iterate_many(json,window);
+     *   for(auto i = stream.begin(); i != stream.end(); ++i) {
+     *      std::string_view v = i.source();
+     *   }
+     *
+     * The returned string_view instance is simply a map to the (unparsed)
+     * source string: it may thus include white-space characters and all manner
+     * of padding.
+     *
+     * This function (source()) is experimental and the usage
+     * may change in future versions of simdjson: we find the API somewhat
+     * awkward and we would like to offer something friendlier.
+     *
+     */
+     simdjson_inline std::string_view source() const noexcept;
 
-#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
-#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
-/* end file simdjson/generic/ondemand/std_deserialize.h for lasx */
+    /**
+     * Returns error of the stream (if any).
+     */
+     inline error_code error() const noexcept;
 
-// Inline definitions
-/* including simdjson/generic/ondemand/array-inl.h for lasx: #include "simdjson/generic/ondemand/array-inl.h" */
-/* begin file simdjson/generic/ondemand/array-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+  private:
+    simdjson_inline iterator(document_stream *s, bool finished) noexcept;
+    /** The document_stream we're iterating through. */
+    document_stream* stream;
+    /** Whether we're finished or not. */
+    bool finished;
 
-/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
-/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+    friend class document;
+    friend class document_stream;
+    friend class json_iterator;
+  };
 
-namespace simdjson {
-namespace lasx {
-namespace ondemand {
+  /**
+   * Start iterating the documents in the stream.
+   */
+  simdjson_inline iterator begin() noexcept;
+  /**
+   * The end of the stream, for iterator comparison purposes.
+   */
+  simdjson_inline iterator end() noexcept;
 
-//
-// ### Live States
-//
-// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
-// always SUCCESS:
-//
-// - Start: This is the state when the array is first found and the iterator is just past the `{`.
-//   In this state, at_start == true.
-// - Next: After we hand a scalar value to the user, or an array/object which they then fully
-//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
-//   depth == iter->depth, at_start == false, and error == SUCCESS.
-// - Unfinished Business: When we hand an array/object to the user which they do not fully
-//   iterate over, we need to finish that iteration by skipping child values until we reach the
-//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
-//
-// ## Error States
-//
-// In error states, we will yield exactly one more value before stopping. iter->depth == depth
-// and at_start is always false. We decrement after yielding the error, moving to the Finished
-// state.
-//
-// - Chained Error: When the array iterator is part of an error chain--for example, in
-//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
-//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
-//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
-// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
-//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
-//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
-//
-// ## Terminal State
-//
-// The terminal state has iter->depth < depth. at_start is always false.
-//
-// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
-//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
-//   error == SUCCESS.
-//
+private:
 
-simdjson_inline array::array(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
+  document_stream &operator=(const document_stream &) = delete; // Disallow copying
+  document_stream(const document_stream &other) = delete; // Disallow copying
 
-simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
-  // We don't need to know if the array is empty to start iteration, but we do want to know if there
-  // is an error--thus `simdjson_unused`.
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
-  simdjson_unused bool has_value;
-  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
-  return array(iter);
-}
-simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
-  bool has_value;
-  SIMDJSON_TRY(iter.started_array().get(has_value));
-  return array(iter);
-}
+  /**
+   * Construct a document_stream. Does not allocate or parse anything until the iterator is
+   * used.
+   *
+   * @param parser is a reference to the parser instance used to generate this document_stream
+   * @param buf is the raw byte buffer we need to process
+   * @param len is the length of the raw byte buffer in bytes
+   * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
+   */
+  simdjson_inline document_stream(
+    ondemand::parser &parser,
+    const uint8_t *buf,
+    size_t len,
+    size_t batch_size,
+    bool allow_comma_separated
+  ) noexcept;
 
-simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
-#endif
-  return array_iterator(iter);
-}
-simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
-  return array_iterator(iter);
-}
-simdjson_inline error_code array::consume() noexcept {
-  auto error = iter.json_iter().skip_child(iter.depth()-1);
-  if(error) { iter.abandon(); }
-  return error;
-}
+  /**
+   * Parse the first document in the buffer. Used by begin(), to handle allocation and
+   * initialization.
+   */
+  inline void start() noexcept;
 
-simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
-  const uint8_t * starting_point{iter.peek_start()};
-  auto error = consume();
-  if(error) { return error; }
-  // After 'consume()', we could be left pointing just beyond the document, but that
-  // is ok because we are not going to dereference the final pointer position, we just
-  // use it to compute the length in bytes.
-  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
-  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
-}
+  /**
+   * Parse the next document found in the buffer previously given to document_stream.
+   *
+   * The content should be a valid JSON document encoded as UTF-8. If there is a
+   * UTF-8 BOM, the parser skips it.
+   *
+   * You do NOT need to pre-allocate a parser.  This function takes care of
+   * pre-allocating a capacity defined by the batch_size defined when creating the
+   * document_stream object.
+   *
+   * The function returns simdjson::EMPTY if there is no more data to be parsed.
+   *
+   * The function returns simdjson::SUCCESS (as integer = 0) in case of success
+   * and indicates that the buffer has successfully been parsed to the end.
+   * Every document it contained has been parsed without error.
+   *
+   * The function returns an error code from simdjson/simdjson.h in case of failure
+   * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth;
+   * the simdjson::error_message function converts these error codes into a string).
+   *
+   * You can also check validity by calling parser.is_valid(). The same parser can
+   * and should be reused for the other documents in the buffer.
+   */
+  inline void next() noexcept;
 
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
-  size_t count{0};
-  // Important: we do not consume any of the values.
-  for(simdjson_unused auto v : *this) { count++; }
-  // The above loop will always succeed, but we want to report errors.
-  if(iter.error()) { return iter.error(); }
-  // We need to move back at the start because we expect users to iterate through
-  // the array after counting the number of elements.
-  iter.reset_array();
-  return count;
-}
-SIMDJSON_POP_DISABLE_WARNINGS
+  /** Move the json_iterator of the document to the location of the next document in the stream. */
+  inline void next_document() noexcept;
 
-simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
-  bool is_not_empty;
-  auto error = iter.reset_array().get(is_not_empty);
-  if(error) { return error; }
-  return !is_not_empty;
-}
+  /** Get the next document index. */
+  inline size_t next_batch_start() const noexcept;
 
-inline simdjson_result<bool> array::reset() & noexcept {
-  return iter.reset_array();
-}
+  /** Pass the next batch through stage 1 with the given parser. */
+  inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept;
 
-inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
-  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
-  json_pointer = json_pointer.substr(1);
-  // - means "the append position" or "the element after the end of the array"
-  // We don't support this, because we're returning a real element, not a position.
-  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
+  // Fields
+  ondemand::parser *parser;
+  const uint8_t *buf;
+  size_t len;
+  size_t batch_size;
+  bool allow_comma_separated;
+  /**
+   * We are going to use just one document instance. The document owns
+   * the json_iterator. It implies that we only ever pass a reference
+   * to the document to the users.
+   */
+  document doc{};
+  /** The error (or lack thereof) from the current document. */
+  error_code error;
+  size_t batch_start{0};
+  size_t doc_index{};
 
-  // Read the array index
-  size_t array_index = 0;
-  size_t i;
-  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
-    uint8_t digit = uint8_t(json_pointer[i] - '0');
-    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
-    if (digit > 9) { return INCORRECT_TYPE; }
-    array_index = array_index*10 + digit;
-  }
+  #ifdef SIMDJSON_THREADS_ENABLED
+  /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */
+  bool use_thread;
 
-  // 0 followed by other digits is invalid
-  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
+  inline void load_from_stage1_thread() noexcept;
 
-  // Empty string is invalid; so is a "/" with no digits before it
-  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
-  // Get the child
-  auto child = at(array_index);
-  // If there is an error, it ends here
-  if(child.error()) {
-    return child;
-  }
+  /** Start a thread to run stage 1 on the next batch. */
+  inline void start_stage1_thread() noexcept;
 
-  // If there is a /, we're not done yet, call recursively.
-  if (i < json_pointer.length()) {
-    child = child.at_pointer(json_pointer.substr(i));
-  }
-  return child;
-}
+  /** Wait for the stage 1 thread to finish and capture the results. */
+  inline void finish_stage1_thread() noexcept;
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
+  /** The error returned from the stage 1 thread. */
+  error_code stage1_thread_error{UNINITIALIZED};
+  /** The thread used to run stage 1 against the next batch in the background. */
+  std::unique_ptr<stage1_worker> worker{new(std::nothrow) stage1_worker()};
+  /**
+   * The parser used to run stage 1 in the background. Will be swapped
+   * with the regular parser when finished.
+   */
+  ondemand::parser stage1_thread_parser{};
 
-simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
-  size_t i = 0;
-  for (auto value : *this) {
-    if (i == index) { return value; }
-    i++;
-  }
-  return INDEX_OUT_OF_BOUNDS;
-}
+  friend struct stage1_worker;
+  #endif // SIMDJSON_THREADS_ENABLED
+
+  friend class parser;
+  friend class document;
+  friend class json_iterator;
+  friend struct simdjson_result<ondemand::document_stream>;
+  friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
+};  // document_stream
 
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
 namespace simdjson {
+template<>
+struct simdjson_result<lasx::ondemand::document_stream> : public lasx::implementation_simdjson_result_base<lasx::ondemand::document_stream> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::document_stream &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
+};
 
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
-  lasx::ondemand::array &&value
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(
-      std::forward<lasx::ondemand::array>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
-  error_code error
-) noexcept
-  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
-{
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
-  if (error()) { return error(); }
-  return first.end();
-}
-simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
-  if (error()) { return error(); }
-  return first.is_empty();
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
-}
-simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
-}
-simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
-/* end file simdjson/generic/ondemand/array-inl.h for lasx */
-/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H
+/* end file simdjson/generic/ondemand/document_stream.h for lasx */
+/* including simdjson/generic/ondemand/field.h for lasx: #include "simdjson/generic/ondemand/field.h" */
+/* begin file simdjson/generic/ondemand/field.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{}
+/**
+ * A JSON field (key/value pair) in an object.
+ *
+ * Returned from object iteration.
+ *
+ * Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
+ */
+class field : public std::pair<raw_json_string, value> {
+public:
+  /**
+   * Create a new invalid field.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline field() noexcept;
 
-simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
-  if (iter.error()) { iter.abandon(); return iter.error(); }
-  return value(iter.child());
-}
-simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
-  return !(*this != other);
-}
-simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
-  return iter.is_open();
-}
-simdjson_inline array_iterator &array_iterator::operator++() noexcept {
-  error_code error;
-  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
-  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
-  if (( error = iter.error() )) { return *this; }
-  if (( error = iter.skip_child() )) { return *this; }
-  if (( error = iter.has_next_element().error() )) { return *this; }
-  return *this;
-}
+  /**
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it.
+   *
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
+   */
+  simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  /**
+   * Get the key as a string_view (for higher speed, consider raw_key).
+   * We deliberately use a more cumbersome name (unescaped_key) to force users
+   * to think twice about using it. The content is stored in the receiver.
+   *
+   * This consumes the key: once you have called unescaped_key(), you cannot
+   * call it again nor can you call key().
+   */
+  template <typename string_type>
+  simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept;
+  /**
+   * Get the key as a raw_json_string. Can be used for direct comparison with
+   * an unescaped C string: e.g., key() == "test". This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key() for a similar function which returns
+   * a more convenient std::string_view result.
+   */
+  simdjson_inline raw_json_string key() const noexcept;
+  /**
+   * Get the unprocessed key as a string_view. This includes the quotes and may include
+   * some spaces after the last quote. This does not count as
+   * consumption of the content: you can safely call it repeatedly.
+   * See escaped_key().
+   */
+  simdjson_inline std::string_view key_raw_json_token() const noexcept;
+  /**
+   * Get the key as a string_view. This does not include the quotes and
+   * the string is unprocessed key so it may contain escape characters
+   * (e.g., \uXXXX or \n). It does not count as a consumption of the content:
+   * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key.
+   */
+  simdjson_inline std::string_view escaped_key() const noexcept;
+  /**
+   * Get the field value.
+   */
+  simdjson_inline ondemand::value &value() & noexcept;
+  /**
+   * @overload ondemand::value &ondemand::value() & noexcept
+   */
+  simdjson_inline ondemand::value value() && noexcept;
+
+protected:
+  simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept;
+  static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
+  static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
+  friend struct simdjson_result<field>;
+  friend class object_iterator;
+};
 
 } // namespace ondemand
 } // namespace lasx
@@ -123835,280 +116616,338 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
-  lasx::ondemand::array_iterator &&value
-) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
-{
-  first.iter.assert_is_valid();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
-  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
-{
-}
+template<>
+struct simdjson_result<lasx::ondemand::field> : public lasx::implementation_simdjson_result_base<lasx::ondemand::field> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::field &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
-  if (error()) { return error(); }
-  return *first;
-}
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return !error(); }
-  return first == other.first;
-}
-simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
-  if (!first.iter.is_valid()) { return error(); }
-  return first != other.first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
-  // Clear the error if there is one, so we don't yield it twice
-  if (error()) { second = SUCCESS; return *this; }
-  ++(first);
-  return *this;
-}
+  simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
+  template<typename string_type>
+  simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> key() noexcept;
+  simdjson_inline simdjson_result<std::string_view> key_raw_json_token() noexcept;
+  simdjson_inline simdjson_result<std::string_view> escaped_key() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> value() noexcept;
+};
 
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
-/* end file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
-/* including simdjson/generic/ondemand/value-inl.h for lasx: #include "simdjson/generic/ondemand/value-inl.h" */
-/* begin file simdjson/generic/ondemand/value-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H
+/* end file simdjson/generic/ondemand/field.h for lasx */
+/* including simdjson/generic/ondemand/object.h for lasx: #include "simdjson/generic/ondemand/object.h" */
+/* begin file simdjson/generic/ondemand/object.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
+/**
+ * A forward-only JSON object field iterator.
+ */
+class object {
+public:
+  /**
+   * Create a new invalid object.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline object() noexcept = default;
 
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
+  simdjson_inline simdjson_result<object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<object_iterator> end() noexcept;
+  /**
+   * Look up a field by name on an object (order-sensitive).
+   *
+   * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
+   * JSON `{ "x": 1, "y": 2, "z": 3 }`:
+   *
+   * ```c++
+   * simdjson::ondemand::parser parser;
+   * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
+   * double z = obj.find_field("z");
+   * double y = obj.find_field("y");
+   * double x = obj.find_field("x");
+   * ```
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
+   * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a
+   * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
+   * is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
 
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
+  /**
+   * Look up a field by name on an object, without regard to key order.
+   *
+   * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
+   * and often appears negligible. It starts out normally, starting out at the last field; but if
+   * the field is not found, it scans from the beginning of the object to see if it missed it. That
+   * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
+   * in question is large. The fact that the extra code is there also bumps the executable size.
+   *
+   * It is the default, however, because it would be highly surprising (and hard to debug) if the
+   * default behavior failed to look up a field just because it was in the wrong order--and many
+   * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
+   *
+   * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
+   * field was not there when they are not in order).
+   *
+   * If you have multiple fields with a matching key ({"x": 1,  "x": 1}) be mindful
+   * that only one field is returned.
+   *
+   * You must consume the fields on an object one at a time. A request for a new key
+   * invalidates previous field values: it makes them unsafe. The value instance you get
+   * from  `content["bids"]` becomes invalid when you call `content["asks"]`. The array
+   * given by content["bids"].get_array() should not be accessed after you have called
+   * content["asks"].get_array(). You can detect such mistakes by first compiling and running
+   * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
+   * OUT_OF_ORDER_ITERATION error is generated.
+   *
+   * You are expected to access keys only once. You should access the value corresponding to a key
+   * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
+   *
+   * If you expect to have keys with escape characters, please review our documentation.
+   *
+   * @param key The key to look up.
+   * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
+   */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
+  /** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
+  simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
 
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
+  /**
+   * Get the value associated with the given JSON pointer. We use the RFC 6901
+   * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
+   * as the root of its own JSON document.
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("/foo/a/1") == 20
+   *
+   * It is allowed for a key to be the empty string:
+   *
+   *   ondemand::parser parser;
+   *   auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
+   *   auto doc = parser.iterate(json);
+   *   doc.at_pointer("//a/1") == 20
+   *
+   * Note that at_pointer() called on the document automatically calls the document's rewind
+   * method between each call. It invalidates all previously accessed arrays, objects and values
+   * that have not been consumed. Yet it is not the case when calling at_pointer on an object
+   * instance: there is no rewind and no invalidation.
+   *
+   * You may call at_pointer more than once on an object, but each time the pointer is advanced
+   * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
+   * key (as well as the current key) can no longer be used with following JSON pointer calls.
+   *
+   * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
+   *
+   * @return The value associated with the given JSON pointer, or:
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   *         - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
+   */
+  inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
 
+  /**
+   * Get the value associated with the given JSONPath expression. We only support
+   * JSONPath queries that trivially convertible to JSON Pointer queries: key
+   * names and array indices.
+   *
+   * @return The value associated with the given JSONPath expression, or:
+   *         - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
+   *         - NO_SUCH_FIELD if a field does not exist in an object
+   *         - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
+   *         - INCORRECT_TYPE if a non-integer is used to access an array
+   */
+  inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
 
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+  /**
+   * Reset the iterator so that we are pointing back at the
+   * beginning of the object. You should still consume values only once even if you
+   * can iterate through the object more than once. If you unescape a string or a key
+   * within the object more than once, you have unsafe code. Note that rewinding an object
+   * means that you may need to reparse it anew: it is not a free operation.
+   *
+   * @returns true if the object contains some elements (not empty)
+   */
+  inline simdjson_result<bool> reset() & noexcept;
+  /**
+   * This method scans the beginning of the object and checks whether the
+   * object is empty.
+   * The runtime complexity is constant time. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   */
+  inline simdjson_result<bool> is_empty() & noexcept;
+  /**
+   * This method scans the object and counts the number of key-value pairs.
+   * The count_fields method should always be called before you have begun
+   * iterating through the object: it is expected that you are pointing at
+   * the beginning of the object.
+   * The runtime complexity is linear in the size of the object. After
+   * calling this function, if successful, the object is 'rewinded' at its
+   * beginning as if it had never been accessed. If the JSON is malformed (e.g.,
+   * there is a missing comma), then an error is returned and it is no longer
+   * safe to continue.
+   *
+   * To check that an object is empty, it is more performant to use
+   * the is_empty() method.
+   *
+   * Performance hint: You should only call count_fields() as a last
+   * resort as it may require scanning the document twice or more.
+   */
+  simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
+  /**
+   * Consumes the object and returns a string_view instance corresponding to the
+   * object as represented in JSON. It points inside the original byte array containing
+   * the JSON document.
+   */
+  simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
-}
-#endif
+protected:
+  /**
+   * Go to the end of the object, no matter where you are right now.
+   */
+  simdjson_inline error_code consume() noexcept;
+  static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
+  static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
+  static simdjson_inline object resume(const value_iterator &iter) noexcept;
+  simdjson_inline object(const value_iterator &iter) noexcept;
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
-}
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
-}
+  simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
+  value_iterator iter{};
 
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
-}
+  friend class value;
+  friend class document;
+  friend struct simdjson_result<object>;
+};
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
-}
+template<>
+struct simdjson_result<lasx::ondemand::object> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::object &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
-}
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> begin() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> end() noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) & noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> operator[](std::string_view key) && noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
+  simdjson_inline simdjson_result<lasx::ondemand::value> at_path(std::string_view json_path) noexcept;
 
+  inline simdjson_result<bool> reset() noexcept;
+  inline simdjson_result<bool> is_empty() noexcept;
+  inline simdjson_result<size_t> count_fields() & noexcept;
+  inline simdjson_result<std::string_view> raw_json() noexcept;
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+};
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H
+/* end file simdjson/generic/ondemand/object.h for lasx */
+/* including simdjson/generic/ondemand/object_iterator.h for lasx: #include "simdjson/generic/ondemand/object_iterator.h" */
+/* begin file simdjson/generic/ondemand/object_iterator.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+class object_iterator {
+public:
+  /**
+   * Create a new invalid object_iterator.
+   *
+   * Exists so you can declare a variable and later assign to it before use.
+   */
+  simdjson_inline object_iterator() noexcept = default;
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
-}
+  //
+  // Iterator interface
+  //
 
-inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
-  auto json_pointer = json_path_to_pointer_conversion(json_path);
-  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
-  return at_pointer(json_pointer);
-}
+  // Reads key and value, yielding them to the user.
+  // MUST ONLY BE CALLED ONCE PER ITERATION.
+  simdjson_inline simdjson_result<field> operator*() noexcept;
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const object_iterator &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const object_iterator &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline object_iterator &operator++() noexcept;
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
-  }
-}
+private:
+  /**
+   * The underlying JSON iterator.
+   *
+   * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
+   * is first used, and never changes afterwards.
+   */
+  value_iterator iter{};
+
+  simdjson_inline object_iterator(const value_iterator &iter) noexcept;
+  friend struct simdjson_result<object_iterator>;
+  friend class object;
+};
 
 } // namespace ondemand
 } // namespace lasx
@@ -124116,251 +116955,137 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
-  lasx::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(
-      std::forward<lasx::ondemand::value>(value)
-    )
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(error)
-{
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
-  if (error()) { return error(); }
-  return {};
-}
+template<>
+struct simdjson_result<lasx::ondemand::object_iterator> : public lasx::implementation_simdjson_result_base<lasx::ondemand::object_iterator> {
+public:
+  simdjson_inline simdjson_result(lasx::ondemand::object_iterator &&value) noexcept; ///< @private
+  simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
+  simdjson_inline simdjson_result() noexcept = default;
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
+  //
+  // Iterator interface
+  //
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
+  // Reads key and value, yielding them to the user.
+  simdjson_inline simdjson_result<lasx::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
+  // Assumes it's being compared with the end. true if depth < iter->depth.
+  simdjson_inline bool operator==(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
+  // Assumes it's being compared with the end. true if depth >= iter->depth.
+  simdjson_inline bool operator!=(const simdjson_result<lasx::ondemand::object_iterator> &) const noexcept;
+  // Checks for ']' and ','
+  simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &operator++() noexcept;
+};
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H
+/* end file simdjson/generic/ondemand/object_iterator.h for lasx */
+/* including simdjson/generic/ondemand/serialization.h for lasx: #include "simdjson/generic/ondemand/serialization.h" */
+/* begin file simdjson/generic/ondemand/serialization.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
 
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+namespace simdjson {
+/**
+ * Create a string-view instance out of a document instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::document& x) noexcept;
+/**
+ * Create a string-view instance out of a value instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. The value must
+ * not have been accessed previously. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::value& x) noexcept;
+/**
+ * Create a string-view instance out of an object instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::object& x) noexcept;
+/**
+ * Create a string-view instance out of an array instance. The string-view instance
+ * contains JSON text that is suitable to be parsed as JSON again. It does not
+ * validate the content.
+ */
+inline simdjson_result<std::string_view> to_json_string(lasx::ondemand::array& x) noexcept;
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::document> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::value> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::object> x);
+inline simdjson_result<std::string_view> to_json_string(simdjson_result<lasx::ondemand::array> x);
+} // namespace simdjson
 
-template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
+/**
+ * We want to support argument-dependent lookup (ADL).
+ * Hence we should define operator<< in the namespace
+ * where the argument (here value, object, etc.) resides.
+ * Credit: @madhur4127
+ * See https://github.com/simdjson/simdjson/issues/1768
+ */
+namespace simdjson { namespace lasx { namespace ondemand {
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
+/**
+ * Print JSON to an output stream.  It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The element.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::value x);
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::value> x);
 #endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::array value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::array> x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The array.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document>&& x);
+#endif
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::document_reference& value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::document_reference>&& x);
+#endif
+/**
+ * Print JSON to an output stream. It does not
+ * validate the content.
+ *
+ * @param out The output stream.
+ * @param value The object.
+ * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
+ */
+inline std::ostream& operator<<(std::ostream& out, simdjson::lasx::ondemand::object value);
+#if SIMDJSON_EXCEPTIONS
+inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::lasx::ondemand::object> x);
+#endif
+}}} // namespace simdjson::lasx::ondemand
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
-
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
-}
-
-simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
-}
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
-}
-
-} // namespace simdjson
+#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H
+/* end file simdjson/generic/ondemand/serialization.h for lasx */
 
 // Deserialization for standard types
 /* including simdjson/generic/ondemand/std_deserialize.h for lasx: #include "simdjson/generic/ondemand/std_deserialize.h" */
@@ -124543,217 +117268,163 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser
 /* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline value::value(const value_iterator &_iter) noexcept
-  : iter{_iter}
-{
-}
-simdjson_inline value value::start(const value_iterator &iter) noexcept {
-  return iter;
-}
-simdjson_inline value value::resume(const value_iterator &iter) noexcept {
-  return iter;
-}
-
-simdjson_inline simdjson_result<array> value::get_array() noexcept {
-  return array::start(iter);
-}
-simdjson_inline simdjson_result<object> value::get_object() noexcept {
-  return object::start(iter);
-}
-simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
-  if (iter.at_start()) {
-    return get_object();
-  } else {
-    return object::resume(iter);
-  }
-}
-
-simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
-  return iter.get_raw_json_string();
-}
-simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
-  return iter.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  return iter.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
-  return iter.get_wobbly_string();
-}
-simdjson_inline simdjson_result<double> value::get_double() noexcept {
-  return iter.get_double();
-}
-simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
-  return iter.get_double_in_string();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
-  return iter.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
-  return iter.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
-  return iter.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
-  return iter.get_int64_in_string();
-}
-simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
-  return iter.get_bool();
-}
-simdjson_inline simdjson_result<bool> value::is_null() noexcept {
-  return iter.is_null();
-}
-
-template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
-template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
-
-
-template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
-template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
-template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
-template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
-template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
-template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
-template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
-template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
-template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the array is first found and the iterator is just past the `{`.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
+//   depth == iter->depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter->depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the array iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
+//   array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter->depth == depth, and at_start == false.
+//
+// ## Terminal State
+//
+// The terminal state has iter->depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
+//   by decrementing depth. In this state, iter->depth < depth, at_start == false, and
+//   error == SUCCESS.
+//
 
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline value::operator T() noexcept(false) {
-  return get<T>();
-}
-simdjson_inline value::operator array() noexcept(false) {
-  return get_array();
-}
-simdjson_inline value::operator object() noexcept(false) {
-  return get_object();
-}
-simdjson_inline value::operator uint64_t() noexcept(false) {
-  return get_uint64();
-}
-simdjson_inline value::operator int64_t() noexcept(false) {
-  return get_int64();
-}
-simdjson_inline value::operator double() noexcept(false) {
-  return get_double();
-}
-simdjson_inline value::operator std::string_view() noexcept(false) {
-  return get_string(false);
-}
-simdjson_inline value::operator raw_json_string() noexcept(false) {
-  return get_raw_json_string();
-}
-simdjson_inline value::operator bool() noexcept(false) {
-  return get_bool();
+simdjson_inline array::array(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
-#endif
 
-simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
-  return get_array().begin();
-}
-simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_array();
-  answer = a.count_elements();
-  // count_elements leaves you pointing inside the array, at the first element.
-  // We need to move back so that the user can create a new array (which requires that
-  // we point at '[').
-  iter.move_at_start();
-  return answer;
+simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
+  // We don't need to know if the array is empty to start iteration, but we do want to know if there
+  // is an error--thus `simdjson_unused`.
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_array().get(has_value) );
+  return array(iter);
 }
-simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
-  simdjson_result<size_t> answer;
-  auto a = get_object();
-  answer = a.count_fields();
-  iter.move_at_start();
-  return answer;
+simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
+  simdjson_unused bool has_value;
+  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
+  return array(iter);
 }
-simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
-  auto a = get_array();
-  return a.at(index);
+simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
+  bool has_value;
+  SIMDJSON_TRY(iter.started_array().get(has_value));
+  return array(iter);
 }
 
-simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
-  return start_or_resume_object().find_field(key);
-}
-simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
-  return start_or_resume_object().find_field(key);
+simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return array_iterator(iter);
 }
-
-simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
+  return array_iterator(iter);
 }
-simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
-  return start_or_resume_object().find_field_unordered(key);
+simdjson_inline error_code array::consume() noexcept {
+  auto error = iter.json_iter().skip_child(iter.depth()-1);
+  if(error) { iter.abandon(); }
+  return error;
 }
 
-simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
-  return start_or_resume_object()[key];
-}
-simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
-  return start_or_resume_object()[key];
+simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  // After 'consume()', we could be left pointing just beyond the document, but that
+  // is ok because we are not going to dereference the final pointer position, we just
+  // use it to compute the length in bytes.
+  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline simdjson_result<json_type> value::type() noexcept {
-  return iter.type();
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the array after counting the number of elements.
+  iter.reset_array();
+  return count;
 }
+SIMDJSON_POP_DISABLE_WARNINGS
 
-simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
+simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_array().get(is_not_empty);
   if(error) { return error; }
-  return ! ((this_type == json_type::array) || (this_type == json_type::object));
+  return !is_not_empty;
 }
 
-simdjson_inline simdjson_result<bool> value::is_string() noexcept {
-  json_type this_type;
-  auto error = type().get(this_type);
-  if(error) { return error; }
-  return (this_type == json_type::string);
+inline simdjson_result<bool> array::reset() & noexcept {
+  return iter.reset_array();
 }
 
+inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  // - means "the append position" or "the element after the end of the array"
+  // We don't support this, because we're returning a real element, not a position.
+  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
 
-simdjson_inline bool value::is_negative() noexcept {
-  return iter.is_negative();
-}
+  // Read the array index
+  size_t array_index = 0;
+  size_t i;
+  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
+    uint8_t digit = uint8_t(json_pointer[i] - '0');
+    // Check for non-digit in array index. If it's there, we're trying to get a field in an object
+    if (digit > 9) { return INCORRECT_TYPE; }
+    array_index = array_index*10 + digit;
+  }
 
-simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
-  return iter.is_integer();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
-  return iter.get_number_type();
-}
-simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
-  return iter.get_number();
-}
+  // 0 followed by other digits is invalid
+  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
 
-simdjson_inline std::string_view value::raw_json_token() noexcept {
-  return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
+  // Empty string is invalid; so is a "/" with no digits before it
+  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
+  // Get the child
+  auto child = at(array_index);
+  // If there is an error, it ends here
+  if(child.error()) {
+    return child;
+  }
+
+  // If there is a /, we're not done yet, call recursively.
+  if (i < json_pointer.length()) {
+    child = child.at_pointer(json_pointer.substr(i));
+  }
+  return child;
 }
 
 inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
@@ -124762,17 +117433,13 @@ inline simdjson_result<value> array::at_path(std::string_view json_path) noexcep
   return at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path) noexcept {
-  json_type t;
-  SIMDJSON_TRY(type().get(t));
-  switch (t) {
-  case json_type::array:
-      return (*this).get_array().at_path(json_path);
-  case json_type::object:
-      return (*this).get_object().at_path(json_path);
-  default:
-      return INVALID_JSON_POINTER;
+simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
+  size_t i = 0;
+  for (auto value : *this) {
+    if (i == index) { return value; }
+    i++;
   }
+  return INDEX_OUT_OF_BOUNDS;
 }
 
 } // namespace ondemand
@@ -124781,248 +117448,132 @@ simdjson_inline simdjson_result<value> value::at_path(std::string_view json_path
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
-  lasx::ondemand::value &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(
-      std::forward<lasx::ondemand::value>(value)
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
+  lasx::ondemand::array &&value
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(
+      std::forward<lasx::ondemand::array>(value)
     )
 {
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::simdjson_result(
+simdjson_inline simdjson_result<lasx::ondemand::array>::simdjson_result(
   error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::value>(error)
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::array>(error)
 {
 }
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::value>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at(size_t index) noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::begin() & noexcept {
+
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::begin() noexcept {
   if (error()) { return error(); }
   return first.begin();
 }
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::value>::end() & noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::array>::end() noexcept {
   if (error()) { return error(); }
-  return {};
+  return first.end();
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(std::string_view key) noexcept {
+simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::array>::count_elements() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.count_elements();
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field(const char *key) noexcept {
+simdjson_inline  simdjson_result<bool> simdjson_result<lasx::ondemand::array>::is_empty() & noexcept {
   if (error()) { return error(); }
-  return first.find_field(key);
+  return first.is_empty();
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at(size_t index) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.at(index);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::find_field_unordered(const char *key) noexcept {
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.find_field_unordered(key);
+  return first.at_pointer(json_pointer);
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](std::string_view key) noexcept {
+simdjson_inline  simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array>::at_path(std::string_view json_path) noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.at_path(json_path);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::operator[](const char *key) noexcept {
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::array>::raw_json() noexcept {
   if (error()) { return error(); }
-  return first[key];
+  return first.raw_json();
 }
+} // namespace simdjson
 
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::value>::get_array() noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::value>::get_object() noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::value>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::value>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::value>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::value>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
+/* end file simdjson/generic/ondemand/array-inl.h for lasx */
+/* including simdjson/generic/ondemand/array_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/array_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/array_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H
 
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>(lasx::ondemand::value &out) noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-template<typename T> simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::value>::get() noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T> simdjson_inline error_code simdjson_result<lasx::ondemand::value>::get(T &out) noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
 
-template<> simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::get<lasx::ondemand::value>() noexcept  {
-  if (error()) { return error(); }
-  return std::move(first);
-}
+simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::value>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::value>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::value>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::value>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
-}
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::array() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::object() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
-}
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
+  if (iter.error()) { iter.abandon(); return iter.error(); }
+  return value(iter.child());
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
+  return !(*this != other);
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
+  return iter.is_open();
 }
-simdjson_inline simdjson_result<lasx::ondemand::value>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline array_iterator &array_iterator::operator++() noexcept {
+  error_code error;
+  // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
+  // However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
+  if (( error = iter.error() )) { return *this; }
+  if (( error = iter.skip_child() )) { return *this; }
+  if (( error = iter.has_next_element().error() )) { return *this; }
+  return *this;
 }
-#endif
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::value>::raw_json() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json();
-}
+namespace simdjson {
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::value>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(
+  lasx::ondemand::array_iterator &&value
+) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>(std::forward<lasx::ondemand::array_iterator>(value))
+{
+  first.iter.assert_is_valid();
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
+  : lasx::implementation_simdjson_result_base<lasx::ondemand::array_iterator>({}, error)
+{
 }
 
-simdjson_inline simdjson_result<int32_t> simdjson_result<lasx::ondemand::value>::current_depth() const noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::array_iterator>::operator*() noexcept {
   if (error()) { return error(); }
-  return first.current_depth();
+  return *first;
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_pointer(
-    std::string_view json_pointer) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_pointer(json_pointer);
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator==(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::value>::at_path(
-      std::string_view json_path) noexcept {
-  if (error()) {
-    return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline bool simdjson_result<lasx::ondemand::array_iterator>::operator!=(const simdjson_result<lasx::ondemand::array_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+simdjson_inline simdjson_result<lasx::ondemand::array_iterator> &simdjson_result<lasx::ondemand::array_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++(first);
+  return *this;
 }
 
 } // namespace simdjson
@@ -126139,7 +118690,7 @@ simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::on
 template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
 simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+  return first;
 }
 simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
   if (error()) { throw simdjson_error(error()); }
@@ -127054,1267 +119605,1062 @@ simdjson_inline std::string_view field::escaped_key() const noexcept {
   return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
 }
 
-
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
-  }
+simdjson_inline value &field::value() & noexcept {
+  return second;
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
+simdjson_inline value field::value() && noexcept {
+  return std::forward<field>(*this).second;
 }
 
-#endif  // SIMDJSON_THREADS_ENABLED
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  lasx::ondemand::field &&value
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(
+      std::forward<lasx::ondemand::field>(value)
+    )
 {
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
 }
-
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
+simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
+  error_code error
+) noexcept :
+    implementation_simdjson_result_base<lasx::ondemand::field>(error)
 {
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
-{
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
+simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+  if (error()) { return error(); }
+  return first.key();
 }
 
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+  if (error()) { return error(); }
+  return first.key_raw_json_token();
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+  if (error()) { return error(); }
+  return first.escaped_key();
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(allow_replacement);
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+template<typename string_type>
+simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+  if (error()) { return error(); }
+  return first.unescaped_key(receiver, allow_replacement);
 }
 
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+  if (error()) { return error(); }
+  return std::move(first.value());
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+/* end file simdjson/generic/ondemand/field-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
+
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
+  : token(std::forward<token_iterator>(other.token)),
+    parser{other.parser},
+    _string_buf_loc{other._string_buf_loc},
+    error{other.error},
+    _depth{other._depth},
+    _root{other._root},
+    _streaming{other._streaming}
+{
+  other.parser = nullptr;
+}
+simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
+  token = other.token;
+  parser = other.parser;
+  _string_buf_loc = other._string_buf_loc;
+  error = other.error;
+  _depth = other._depth;
+  _root = other._root;
+  _streaming = other._streaming;
+  other.parser = nullptr;
   return *this;
 }
 
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
-}
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
+  : token(buf, &_parser->implementation->structural_indexes[0]),
+    parser{_parser},
+    _string_buf_loc{parser->string_buf.get()},
+    _depth{1},
+    _root{parser->implementation->structural_indexes.get()},
+    _streaming{false}
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
+    : token(buf, &_parser->implementation->structural_indexes[0]),
+      parser{_parser},
+      _string_buf_loc{parser->string_buf.get()},
+      _depth{1},
+      _root{parser->implementation->structural_indexes.get()},
+      _streaming{streaming}
+
+{
+  logger::log_headers();
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
+inline void json_iterator::rewind() noexcept {
+  token.set_position( root_position() );
+  logger::log_headers(); // We start again
+  _string_buf_loc = parser->string_buf.get();
+  _depth = 1;
+}
 
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
+inline bool json_iterator::balanced() const noexcept {
+  token_iterator ti(token);
+  int32_t count{0};
+  ti.set_position( root_position() );
+  while(ti.peek() <= peek_last()) {
+    switch (*ti.return_current_and_advance())
+    {
+    case '[': case '{':
+      count++;
+      break;
+    case ']': case '}':
+      count--;
+      break;
+    default:
+      break;
+    }
   }
-  #endif // SIMDJSON_THREADS_ENABLED
+  return count == 0;
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
 
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
+// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
+// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
+// skip_child() function is not marked inline).
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
+  if (depth() <= parent_depth) { return SUCCESS; }
+  switch (*return_current_and_advance()) {
+    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+    // *missing* braces, then future lookups are not in the object/arrays they think they are,
+    // violating the rule "validate enough structure that the user can be confident they are
+    // looking at the right values."
+    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+
+    // For the first open array/object in a value, we've already incremented depth, so keep it the same
+    // We never stop at colon, but if we did, it wouldn't affect depth
+    case '[': case '{': case ':':
+      logger::log_start_value(*this, "skip");
+      break;
+    // If there is a comma, we have just finished a value in an array/object, and need to get back in
+    case ',':
+      logger::log_value(*this, "skip");
+      break;
+    // ] or } means we just finished a value and need to jump out of the array/object
+    case ']': case '}':
+      logger::log_end_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+#if SIMDJSON_CHECK_EOF
+      // If there are no more tokens, the parent is incomplete.
+      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
+#endif // SIMDJSON_CHECK_EOF
+      break;
+    case '"':
+      if(*peek() == ':') {
+        // We are at a key!!!
+        // This might happen if you just started an object and you skip it immediately.
+        // Performance note: it would be nice to get rid of this check as it is somewhat
+        // expensive.
+        // https://github.com/simdjson/simdjson/issues/1742
+        logger::log_value(*this, "key");
+        return_current_and_advance(); // eat up the ':'
+        break; // important!!!
       }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
+      simdjson_fallthrough;
+    // Anything else must be a scalar value
+    default:
+      // For the first scalar, we will have incremented depth already, so we decrement it here.
+      logger::log_value(*this, "skip");
+      _depth--;
+      if (depth() <= parent_depth) { return SUCCESS; }
+      break;
+  }
 
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
+  // Now that we've considered the first value, we only increment/decrement for arrays/objects
+  while (position() < end_position()) {
+    switch (*return_current_and_advance()) {
+      case '[': case '{':
+        logger::log_start_value(*this, "skip");
+        _depth++;
+        break;
+      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
+      // *missing* braces, then future lookups are not in the object/arrays they think they are,
+      // violating the rule "validate enough structure that the user can be confident they are
+      // looking at the right values."
+      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+      case ']': case '}':
+        logger::log_end_value(*this, "skip");
+        _depth--;
+        if (depth() <= parent_depth) { return SUCCESS; }
+        break;
+      default:
+        logger::log_value(*this, "skip", "");
+        break;
     }
   }
+
+  return report_error(TAPE_ERROR, "not enough close braces");
 }
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
+
+SIMDJSON_POP_DISABLE_WARNINGS
+
+simdjson_inline bool json_iterator::at_root() const noexcept {
+  return position() == root_position();
 }
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
+
+simdjson_inline bool json_iterator::is_single_token() const noexcept {
+  return parser->implementation->n_structural_indexes == 1;
 }
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
+
+simdjson_inline bool json_iterator::streaming() const noexcept {
+  return _streaming;
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
+
+simdjson_inline token_position json_iterator::root_position() const noexcept {
+  return _root;
 }
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
+
+simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
 }
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
+
+simdjson_inline void json_iterator::assert_at_root() const noexcept {
+  SIMDJSON_ASSUME( _depth == 1 );
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
+  // has side effects that will be discarded.
+  SIMDJSON_ASSUME( token.position() == _root );
+#endif
 }
 
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
+simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
+  assert_valid_position(token._position + required_tokens - 1);
 }
-template<typename T>
-simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first).get<T>();
+
+simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
+  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
+#endif
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
+
+simdjson_inline bool json_iterator::at_end() const noexcept {
+  return position() == end_position();
 }
-template<typename T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first).get<T>(out);
+simdjson_inline token_position json_iterator::end_position() const noexcept {
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  return &parser->implementation->structural_indexes[n_structural_indexes];
 }
 
-template<> simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() & noexcept = delete;
-template<> simdjson_deprecated simdjson_inline simdjson_result<lasx::ondemand::document> simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document>(first);
-}
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) & noexcept = delete;
-template<> simdjson_inline error_code simdjson_result<lasx::ondemand::document>::get<lasx::ondemand::document>(lasx::ondemand::document &out) && noexcept {
-  if (error()) { return error(); }
-  out = std::forward<lasx::ondemand::document>(first);
-  return SUCCESS;
+inline std::string json_iterator::to_string() const noexcept {
+  if( !is_alive() ) { return "dead json_iterator instance"; }
+  const char * current_structural = reinterpret_cast<const char *>(token.peek());
+  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
+          + std::string(", structural : '") + std::string(current_structural,1)
+          + std::string("', offset : ") + std::to_string(token.current_offset())
+          + std::string("', error : ") + error_message(error)
+          + std::string(" ]");
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
+inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
+  if (!is_alive()) {    // Unrecoverable error
+    if (!at_root()) {
+      return reinterpret_cast<const char *>(token.peek(-1));
+    } else {
+      return reinterpret_cast<const char *>(token.peek());
+    }
+  }
+  if (at_end()) {
+    return OUT_OF_BOUNDS;
+  }
+  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
+simdjson_inline bool json_iterator::is_alive() const noexcept {
+  return parser;
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
+simdjson_inline void json_iterator::abandon() noexcept {
+  parser = nullptr;
+  _depth = 0;
 }
 
-simdjson_inline bool simdjson_result<lasx::ondemand::document>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
+simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens();
+#endif // SIMDJSON_CHECK_EOF
+  return token.return_current_and_advance();
 }
 
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
+simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
+  // deliberately done without safety guard:
+  return token.peek();
 }
 
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
+simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek(delta);
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_more_tokens(delta+1);
+#endif // #if SIMDJSON_CHECK_EOF
+  return token.peek_length(delta);
 }
 
+simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
+  // todo: currently we require end-of-string buffering, but the following
+  // assert_valid_position should be turned on if/when we lift that condition.
+  // assert_valid_position(position);
+  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
+  // is ON by default, we have no choice but to disable it for real with a comment.
+  return token.peek(position);
+}
 
-#if SIMDJSON_EXCEPTIONS
-template <class T, typename std::enable_if<std::is_same<T, lasx::ondemand::document>::value == false>::type>
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator T() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_length(position);
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
+#if SIMDJSON_CHECK_EOF
+  assert_valid_position(position);
+#endif // SIMDJSON_CHECK_EOF
+  return token.peek_root_length(position);
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::last_position() const noexcept {
+  // The following line fails under some compilers...
+  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
+  // since it has side-effects.
+  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
+  SIMDJSON_ASSUME(n_structural_indexes > 0);
+  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
+  return token.peek(last_position());
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
+  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
+  SIMDJSON_ASSUME(_depth == parent_depth + 1);
+  _depth = parent_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+  _depth = child_depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline depth_t json_iterator::depth() const noexcept {
+  return _depth;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
+  return _string_buf_loc;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  error = _error;
+  return error;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document>::operator lasx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline token_position json_iterator::position() const noexcept {
+  return token.position();
 }
+
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape(in, _string_buf_loc, allow_replacement);
 #endif
+}
 
+simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  auto result = parser->unescape_wobbly(in, _string_buf_loc);
+  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
+  return result;
+#else
+  return parser->unescape_wobbly(in, _string_buf_loc);
+#endif
+}
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
+  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
+  SIMDJSON_ASSUME(_depth == child_depth - 1);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
+  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
+  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
+#endif
+#endif
+  token.set_position(position);
+  _depth = child_depth;
 }
 
-simdjson_inline bool simdjson_result<lasx::ondemand::document>::at_end() const noexcept {
-  if (error()) { return error(); }
-  return first.at_end();
+simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
+  if (*peek() == c) {
+    return_current_and_advance();
+    return SUCCESS;
+  }
+  return TAPE_ERROR;
 }
 
+#if SIMDJSON_DEVELOPMENT_CHECKS
 
-simdjson_inline int32_t simdjson_result<lasx::ondemand::document>::current_depth() const noexcept {
-  if (error()) { return error(); }
-  return first.current_depth();
+simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
+  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
+  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+#endif
+
+
+simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
+  SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
+  logger::log_error(*this, message);
+  return _error;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document>::at_path(std::string_view json_path) noexcept {
-  if (error()) { return error(); }
-  return first.at_path(json_path);
+
+simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
+  // This function is not expected to be called in performance-sensitive settings.
+  // Let us guard against silly cases:
+  if((N < max_len) || (N == 0)) { return false; }
+  // Copy to the buffer.
+  std::memcpy(tmpbuf, json, max_len);
+  if(N > max_len) { // We pad whatever remains with ' '.
+    std::memset(tmpbuf + max_len, ' ', N - max_len);
+  }
+  return true;
 }
 
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-
 namespace simdjson {
-namespace lasx {
-namespace ondemand {
 
-simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
-simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
-simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
-simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
-simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
-/**
- * The document_reference instances are used primarily/solely for streams of JSON
- * documents.
- * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
- * give an error, so we check for trailing content.
- *
- * However, for streams of JSON documents, we want to be able to start from
- * "321" "321" "321"
- * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
- * successfully each time.
- *
- * To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
- * this indicates that we allow trailing content.
- */
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
-simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
-simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
-template <typename string_type>
-simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
-simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
-simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
-simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
-simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
-simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
-template<> simdjson_inline simdjson_result<array> document_reference::get() & noexcept { return get_array(); }
-template<> simdjson_inline simdjson_result<object> document_reference::get() & noexcept { return get_object(); }
-template<> simdjson_inline simdjson_result<raw_json_string> document_reference::get() & noexcept { return get_raw_json_string(); }
-template<> simdjson_inline simdjson_result<std::string_view> document_reference::get() & noexcept { return get_string(false); }
-template<> simdjson_inline simdjson_result<double> document_reference::get() & noexcept { return get_double(); }
-template<> simdjson_inline simdjson_result<uint64_t> document_reference::get() & noexcept { return get_uint64(); }
-template<> simdjson_inline simdjson_result<int64_t> document_reference::get() & noexcept { return get_int64(); }
-template<> simdjson_inline simdjson_result<bool> document_reference::get() & noexcept { return get_bool(); }
-template<> simdjson_inline simdjson_result<value> document_reference::get() & noexcept { return get_value(); }
-#if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline document_reference::operator T() noexcept(false) { return get<T>(); }
-simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
-simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
-simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
-simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
-simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
-simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
-simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
-simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
-simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
-#endif
-simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
-simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
-simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
-simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
-simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
-simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
-simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
-simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
-simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
-simdjson_inline simdjson_result<bool> document_reference::is_string() noexcept { return doc->is_string(); }
-simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
-simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
-simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
-simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
-simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
-simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
-simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
-simdjson_inline simdjson_result<value> document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); }
-simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
-simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(lasx::ondemand::json_iterator &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(std::forward<lasx::ondemand::json_iterator>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_iterator>(error) {}
 
-} // namespace ondemand
-} // namespace lasx
 } // namespace simdjson
 
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/json_type-inl.h for lasx: #include "simdjson/generic/ondemand/json_type-inl.h" */
+/* begin file simdjson/generic/ondemand/json_type-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
 
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::simdjson_result(lasx::ondemand::document_reference value, error_code error)
-  noexcept : implementation_simdjson_result_base<lasx::ondemand::document_reference>(std::forward<lasx::ondemand::document_reference>(value), error) {}
-
+namespace lasx {
+namespace ondemand {
 
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_elements() & noexcept {
-  if (error()) { return error(); }
-  return first.count_elements();
-}
-simdjson_inline simdjson_result<size_t> simdjson_result<lasx::ondemand::document_reference>::count_fields() & noexcept {
-  if (error()) { return error(); }
-  return first.count_fields();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at(size_t index) & noexcept {
-  if (error()) { return error(); }
-  return first.at(index);
-}
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::rewind() noexcept {
-  if (error()) { return error(); }
-  first.rewind();
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::begin() & noexcept {
-  if (error()) { return error(); }
-  return first.begin();
-}
-simdjson_inline simdjson_result<lasx::ondemand::array_iterator> simdjson_result<lasx::ondemand::document_reference>::end() & noexcept {
-  return {};
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field_unordered(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field_unordered(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::operator[](const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first[key];
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(std::string_view key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::find_field(const char *key) & noexcept {
-  if (error()) { return error(); }
-  return first.find_field(key);
-}
-simdjson_inline simdjson_result<lasx::ondemand::array> simdjson_result<lasx::ondemand::document_reference>::get_array() & noexcept {
-  if (error()) { return error(); }
-  return first.get_array();
-}
-simdjson_inline simdjson_result<lasx::ondemand::object> simdjson_result<lasx::ondemand::document_reference>::get_object() & noexcept {
-  if (error()) { return error(); }
-  return first.get_object();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64();
-}
-simdjson_inline simdjson_result<uint64_t> simdjson_result<lasx::ondemand::document_reference>::get_uint64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_uint64_in_string();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64();
-}
-simdjson_inline simdjson_result<int64_t> simdjson_result<lasx::ondemand::document_reference>::get_int64_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_int64_in_string();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double() noexcept {
-  if (error()) { return error(); }
-  return first.get_double();
-}
-simdjson_inline simdjson_result<double> simdjson_result<lasx::ondemand::document_reference>::get_double_in_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_double_in_string();
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_string(bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(allow_replacement);
-}
-template <typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
-  if (error()) { return error(); }
-  return first.get_string(receiver, allow_replacement);
-}
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::get_wobbly_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_wobbly_string();
-}
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::document_reference>::get_raw_json_string() noexcept {
-  if (error()) { return error(); }
-  return first.get_raw_json_string();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::get_bool() noexcept {
-  if (error()) { return error(); }
-  return first.get_bool();
-}
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::get_value() noexcept {
-  if (error()) { return error(); }
-  return first.get_value();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_null() noexcept {
-  if (error()) { return error(); }
-  return first.is_null();
-}
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>();
-}
-template<typename T>
-simdjson_inline simdjson_result<T> simdjson_result<lasx::ondemand::document_reference>::get() && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document_reference>(first).get<T>();
-}
-template <class T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) & noexcept {
-  if (error()) { return error(); }
-  return first.get<T>(out);
-}
-template <class T>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(T &out) && noexcept {
-  if (error()) { return error(); }
-  return std::forward<lasx::ondemand::document_reference>(first).get<T>(out);
-}
-simdjson_inline simdjson_result<lasx::ondemand::json_type> simdjson_result<lasx::ondemand::document_reference>::type() noexcept {
-  if (error()) { return error(); }
-  return first.type();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_scalar() noexcept {
-  if (error()) { return error(); }
-  return first.is_scalar();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_string() noexcept {
-  if (error()) { return error(); }
-  return first.is_string();
-}
-template <>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) & noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-template <>
-simdjson_inline error_code simdjson_result<lasx::ondemand::document_reference>::get(lasx::ondemand::document_reference &out) && noexcept {
-  if (error()) { return error(); }
-  out = first;
-  return SUCCESS;
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_negative() noexcept {
-  if (error()) { return error(); }
-  return first.is_negative();
-}
-simdjson_inline simdjson_result<bool> simdjson_result<lasx::ondemand::document_reference>::is_integer() noexcept {
-  if (error()) { return error(); }
-  return first.is_integer();
-}
-simdjson_inline simdjson_result<lasx::number_type> simdjson_result<lasx::ondemand::document_reference>::get_number_type() noexcept {
-  if (error()) { return error(); }
-  return first.get_number_type();
-}
-simdjson_inline simdjson_result<lasx::ondemand::number> simdjson_result<lasx::ondemand::document_reference>::get_number() noexcept {
-  if (error()) { return error(); }
-  return first.get_number();
+inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
+    switch (type) {
+        case json_type::array: out << "array"; break;
+        case json_type::object: out << "object"; break;
+        case json_type::number: out << "number"; break;
+        case json_type::string: out << "string"; break;
+        case json_type::boolean: out << "boolean"; break;
+        case json_type::null: out << "null"; break;
+        default: SIMDJSON_UNREACHABLE();
+    }
+    return out;
 }
+
 #if SIMDJSON_EXCEPTIONS
-template <class T>
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator T() noexcept(false) {
-  static_assert(std::is_same<T, lasx::ondemand::document_reference>::value == false, "You should not call get<T> when T is a document");
-  static_assert(std::is_same<T, lasx::ondemand::document>::value == false, "You should not call get<T> when T is a document");
-  if (error()) { throw simdjson_error(error()); }
-  return first.get<T>();
+inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
+    return out << type.value();
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::array() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+#endif
+
+
+
+simdjson_inline number_type number::get_number_type() const noexcept {
+  return type;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::object() & noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool number::is_uint64() const noexcept {
+  return get_number_type() == number_type::unsigned_integer;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator uint64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline uint64_t number::get_uint64() const noexcept {
+  return payload.unsigned_integer;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator int64_t() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline number::operator uint64_t() const noexcept {
+  return get_uint64();
+}
+
+simdjson_inline bool number::is_int64() const noexcept {
+  return get_number_type() == number_type::signed_integer;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator double() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline int64_t number::get_int64() const noexcept {
+  return payload.signed_integer;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator std::string_view() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline number::operator int64_t() const noexcept {
+  return get_int64();
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::raw_json_string() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline bool number::is_double() const noexcept {
+    return get_number_type() == number_type::floating_point_number;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator bool() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline double number::get_double() const noexcept {
+  return payload.floating_point_number;
 }
-simdjson_inline simdjson_result<lasx::ondemand::document_reference>::operator lasx::ondemand::value() noexcept(false) {
-  if (error()) { throw simdjson_error(error()); }
-  return first;
+
+simdjson_inline number::operator double() const noexcept {
+  return get_double();
 }
-#endif
 
-simdjson_inline simdjson_result<const char *> simdjson_result<lasx::ondemand::document_reference>::current_location() noexcept {
-  if (error()) { return error(); }
-  return first.current_location();
+simdjson_inline double number::as_double() const noexcept {
+  if(is_double()) {
+    return payload.floating_point_number;
+  }
+  if(is_int64()) {
+    return double(payload.signed_integer);
+  }
+  return double(payload.unsigned_integer);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::document_reference>::raw_json_token() noexcept {
-  if (error()) { return error(); }
-  return first.raw_json_token();
+simdjson_inline void number::append_s64(int64_t value) noexcept {
+  payload.signed_integer = value;
+  type = number_type::signed_integer;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
-  if (error()) { return error(); }
-  return first.at_pointer(json_pointer);
+simdjson_inline void number::append_u64(uint64_t value) noexcept {
+  payload.unsigned_integer = value;
+  type = number_type::unsigned_integer;
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::document_reference>::at_path(std::string_view json_path) noexcept {
-  if (error()) {
-      return error();
-  }
-  return first.at_path(json_path);
+simdjson_inline void number::append_double(double value) noexcept {
+  payload.floating_point_number = value;
+  type = number_type::floating_point_number;
+}
+
+simdjson_inline void number::skip_double() noexcept {
+  type = number_type::floating_point_number;
 }
 
+} // namespace ondemand
+} // namespace lasx
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
-/* end file simdjson/generic/ondemand/document-inl.h for lasx */
-/* including simdjson/generic/ondemand/document_stream-inl.h for lasx: #include "simdjson/generic/ondemand/document_stream-inl.h" */
-/* begin file simdjson/generic/ondemand/document_stream-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(lasx::ondemand::json_type &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(std::forward<lasx::ondemand::json_type>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::json_type>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::json_type>(error) {}
+
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H
+/* end file simdjson/generic/ondemand/json_type-inl.h for lasx */
+/* including simdjson/generic/ondemand/logger-inl.h for lasx: #include "simdjson/generic/ondemand/logger-inl.h" */
+/* begin file simdjson/generic/ondemand/logger-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-#include <algorithm>
-#include <stdexcept>
+#include <memory>
+#include <cstring>
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
+namespace logger {
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void stage1_worker::finish() {
-  // After calling "run" someone would call finish() to wait
-  // for the end of the processing.
-  // This function will wait until either the thread has done
-  // the processing or, else, the destructor has been called.
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  cond_var.wait(lock, [this]{return has_work == false;});
-}
-
-inline stage1_worker::~stage1_worker() {
-  // The thread may never outlive the stage1_worker instance
-  // and will always be stopped/joined before the stage1_worker
-  // instance is gone.
-  stop_thread();
-}
-
-inline void stage1_worker::start_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  if(thread.joinable()) {
-    return; // This should never happen but we never want to create more than one thread.
-  }
-  thread = std::thread([this]{
-      while(true) {
-        std::unique_lock<std::mutex> thread_lock(locking_mutex);
-        // We wait for either "run" or "stop_thread" to be called.
-        cond_var.wait(thread_lock, [this]{return has_work || !can_work;});
-        // If, for some reason, the stop_thread() method was called (i.e., the
-        // destructor of stage1_worker is called, then we want to immediately destroy
-        // the thread (and not do any more processing).
-        if(!can_work) {
-          break;
-        }
-        this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
-              this->_next_batch_start);
-        this->has_work = false;
-        // The condition variable call should be moved after thread_lock.unlock() for performance
-        // reasons but thread sanitizers may report it as a data race if we do.
-        // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-        cond_var.notify_one(); // will notify "finish"
-        thread_lock.unlock();
-      }
-    }
-  );
-}
-
+static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+static constexpr const int LOG_EVENT_LEN = 20;
+static constexpr const int LOG_BUFFER_LEN = 30;
+static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
+static int log_depth = 0; // Not threadsafe. Log only.
 
-inline void stage1_worker::stop_thread() {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  // We have to make sure that all locks can be released.
-  can_work = false;
-  has_work = false;
-  cond_var.notify_all();
-  lock.unlock();
-  if(thread.joinable()) {
-    thread.join();
+// Helper to turn unprintable or newline characters into spaces
+static inline char printable_char(char c) {
+  if (c >= 0x20) {
+    return c;
+  } else {
+    return ' ';
   }
 }
 
-inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) {
-  std::unique_lock<std::mutex> lock(locking_mutex);
-  owner = ds;
-  _next_batch_start = next_batch_start;
-  stage1_thread_parser = stage1;
-  has_work = true;
-  // The condition variable call should be moved after thread_lock.unlock() for performance
-  // reasons but thread sanitizers may report it as a data race if we do.
-  // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock
-  cond_var.notify_one(); // will notify the thread lock that we have work
-  lock.unlock();
-}
-
-#endif  // SIMDJSON_THREADS_ENABLED
-
-simdjson_inline document_stream::document_stream(
-  ondemand::parser &_parser,
-  const uint8_t *_buf,
-  size_t _len,
-  size_t _batch_size,
-  bool _allow_comma_separated
-) noexcept
-  : parser{&_parser},
-    buf{_buf},
-    len{_len},
-    batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
-    allow_comma_separated{_allow_comma_separated},
-    error{SUCCESS}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change
-    #endif
+template<typename... Args>
+static inline std::string string_format(const std::string& format, const Args&... args)
 {
-#ifdef SIMDJSON_THREADS_ENABLED
-  if(worker.get() == nullptr) {
-    error = MEMALLOC;
-  }
-#endif
+  SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+  int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
+  auto size = static_cast<size_t>(size_s);
+  if (size <= 0) return std::string();
+  std::unique_ptr<char[]> buf(new char[size]);
+  std::snprintf(buf.get(), size, format.c_str(), args...);
+  SIMDJSON_POP_DISABLE_WARNINGS
+  return std::string(buf.get(), buf.get() + size - 1);
 }
 
-simdjson_inline document_stream::document_stream() noexcept
-  : parser{nullptr},
-    buf{nullptr},
-    len{0},
-    batch_size{0},
-    allow_comma_separated{false},
-    error{UNINITIALIZED}
-    #ifdef SIMDJSON_THREADS_ENABLED
-    , use_thread(false)
-    #endif
+static inline log_level get_log_level_from_env()
 {
+  SIMDJSON_PUSH_DISABLE_WARNINGS
+  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
+      char *lvl = getenv("SIMDJSON_LOG_LEVEL");
+  SIMDJSON_POP_DISABLE_WARNINGS
+  if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
+  return log_level::info;
 }
 
-simdjson_inline document_stream::~document_stream() noexcept
+static inline log_level log_threshold()
 {
-  #ifdef SIMDJSON_THREADS_ENABLED
-  worker.reset();
-  #endif
-}
-
-inline size_t document_stream::size_in_bytes() const noexcept {
-  return len;
+  static log_level threshold = get_log_level_from_env();
+  return threshold;
 }
 
-inline size_t document_stream::truncated_bytes() const noexcept {
-  if(error == CAPACITY) { return len - batch_start; }
-  return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1];
+static inline bool should_log(log_level level)
+{
+  return level >= log_threshold();
 }
 
-simdjson_inline document_stream::iterator::iterator() noexcept
-  : stream{nullptr}, finished{true} {
+inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
-  : stream{_stream}, finished{is_end} {
+inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "", type, detail, log_level::info);
 }
-
-simdjson_inline simdjson_result<ondemand::document_reference> document_stream::iterator::operator*() noexcept {
-  return simdjson_result<ondemand::document_reference>(stream->doc, stream->error);
+inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
 }
 
-simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
-  // If there is an error, then we want the iterator
-  // to be finished, no matter what. (E.g., we do not
-  // keep generating documents with errors, or go beyond
-  // a document with errors.)
-  //
-  // Users do not have to call "operator*()" when they use operator++,
-  // so we need to end the stream in the operator++ function.
-  //
-  // Note that setting finished = true is essential otherwise
-  // we would enter an infinite loop.
-  if (stream->error) { finished = true; }
-  // Note that stream->error() is guarded against error conditions
-  // (it will immediately return if stream->error casts to false).
-  // In effect, this next function does nothing when (stream->error)
-  // is true (hence the risk of an infinite loop).
-  stream->next();
-  // If that was the last document, we're finished.
-  // It is the only type of error we do not want to appear
-  // in operator*.
-  if (stream->error == EMPTY) { finished = true; }
-  // If we had any other kind of error (not EMPTY) then we want
-  // to pass it along to the operator* and we cannot mark the result
-  // as "finished" just yet.
-  return *this;
+inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
+  log_line(iter, index, depth, "+", type, detail, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
-
-simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
-  return finished != other.finished;
+inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
+  if (LOG_ENABLED) { log_depth++; }
 }
 
-simdjson_inline document_stream::iterator document_stream::begin() noexcept {
-  start();
-  // If there are no documents, we're finished.
-  return iterator(this, error == EMPTY);
+inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  if (LOG_ENABLED) { log_depth--; }
+  log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
 }
 
-simdjson_inline document_stream::iterator document_stream::end() noexcept {
-  return iterator(this, true);
+inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
 }
-
-inline void document_stream::start() noexcept {
-  if (error) { return; }
-  error = parser->allocate(batch_size);
-  if (error) { return; }
-  // Always run the first stage 1 parse immediately
-  batch_start = 0;
-  error = run_stage1(*parser, batch_start);
-  while(error == EMPTY) {
-    // In exceptional cases, we may start with an empty block
-    batch_start = next_batch_start();
-    if (batch_start >= len) { return; }
-    error = run_stage1(*parser, batch_start);
-  }
-  if (error) { return; }
-  doc_index = batch_start;
-  doc = document(json_iterator(&buf[batch_start], parser));
-  doc.iter._streaming = true;
-
-  #ifdef SIMDJSON_THREADS_ENABLED
-  if (use_thread && next_batch_start() < len) {
-    // Kick off the first thread on next batch if needed
-    error = stage1_thread_parser.allocate(batch_size);
-    if (error) { return; }
-    worker->start_thread();
-    start_stage1_thread();
-    if (error) { return; }
-  }
-  #endif // SIMDJSON_THREADS_ENABLED
+inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
+  log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
 }
 
-inline void document_stream::next() noexcept {
-  // We always enter at once once in an error condition.
-  if (error) { return; }
-  next_document();
-  if (error) { return; }
-  auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get();
-  doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index];
-
-  // Check if at end of structural indexes (i.e. at end of batch)
-  if(cur_struct_index >= static_cast<int64_t>(parser->implementation->n_structural_indexes)) {
-    error = EMPTY;
-    // Load another batch (if available)
-    while (error == EMPTY) {
-      batch_start = next_batch_start();
-      if (batch_start >= len) { break; }
-      #ifdef SIMDJSON_THREADS_ENABLED
-      if(use_thread) {
-        load_from_stage1_thread();
-      } else {
-        error = run_stage1(*parser, batch_start);
-      }
-      #else
-      error = run_stage1(*parser, batch_start);
-      #endif
-      /**
-       * Whenever we move to another window, we need to update all pointers to make
-       * it appear as if the input buffer started at the beginning of the window.
-       *
-       * Take this input:
-       *
-       * {"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]  [15,  11,   12, 13]  [154,  110,   112, 1311]
-       *
-       * Say you process the following window...
-       *
-       * '{"z":5}  {"1":1,"2":2,"4":4} [7,  10,   9]'
-       *
-       * When you do so, the json_iterator has a pointer at the beginning of the memory region
-       * (pointing at the beginning of '{"z"...'.
-       *
-       * When you move to the window that starts at...
-       *
-       * '[7,  10,   9]  [15,  11,   12, 13] ...
-       *
-       * then it is not sufficient to just run stage 1. You also need to re-anchor the
-       * json_iterator so that it believes we are starting at '[7,  10,   9]...'.
-       *
-       * Under the DOM front-end, this gets done automatically because the parser owns
-       * the pointer the data, and when you call stage1 and then stage2 on the same
-       * parser, then stage2 will run on the pointer acquired by stage1.
-       *
-       * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that
-       * we used. But json_iterator has no callback when stage1 is called on the parser.
-       * In fact, I think that the parser is unaware of json_iterator.
-       *
-       *
-       * So we need to re-anchor the json_iterator after each call to stage 1 so that
-       * all of the pointers are in sync.
-       */
-      doc.iter = json_iterator(&buf[batch_start], parser);
-      doc.iter._streaming = true;
-      /**
-       * End of resync.
-       */
-
-      if (error) { continue; } // If the error was EMPTY, we may want to load another batch.
-      doc_index = batch_start;
-    }
-  }
+inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_event(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-inline void document_stream::next_document() noexcept {
-  // Go to next place where depth=0 (document depth)
-  error = doc.iter.skip_child(0);
-  if (error) { return; }
-  // Always set depth=1 at the start of document
-  doc.iter._depth = 1;
-  // consume comma if comma separated is allowed
-  if (allow_comma_separated) { doc.iter.consume_character(','); }
-  // Resets the string buffer at the beginning, thus invalidating the strings.
-  doc.iter._string_buf_loc = parser->string_buf.get();
-  doc.iter._root = doc.iter.position();
+inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
+  log_value(iter.json_iter(), type, detail, delta, depth_delta);
 }
 
-inline size_t document_stream::next_batch_start() const noexcept {
-  return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes];
+inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_start_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept {
-  // This code only updates the structural index in the parser, it does not update any json_iterator
-  // instance.
-  size_t remaining = len - _batch_start;
-  if (remaining <= batch_size) {
-    return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
-  } else {
-    return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
-  }
+inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
+  log_end_value(iter.json_iter(), type, delta, depth_delta);
 }
 
-simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
-  return stream->doc_index;
+inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
+  log_error(iter.json_iter(), error, detail, delta, depth_delta);
 }
 
-simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
-  auto depth = stream->doc.iter.depth();
-  auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get();
-
-  // If at root, process the first token to determine if scalar value
-  if (stream->doc.iter.at_root()) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':   // Depth=1 already at start of document
-        break;
-      case '}': case ']':
-        depth--;
-        break;
-      default:    // Scalar value document
-        // TODO: We could remove trailing whitespaces
-        // This returns a string spanning from start of value to the beginning of the next document (excluded)
-        {
-          auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
-          // normally the length would be next_index - current_index() - 1, except for the last document
-          size_t svlen = next_index - current_index();
-          const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
-          while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
-            svlen--;
-          }
-          return std::string_view(start, svlen);
-        }
-    }
-    cur_struct_index++;
-  }
+inline void log_headers() noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(log_level::info))) {
+      // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
+      static bool displayed_hint{false};
+      log_depth = 0;
+      printf("\n");
+      if (!displayed_hint) {
+        // We only print this helpful header once.
+        printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
+        printf("# +array says 'this is where we were when we discovered the start array'\n");
+        printf(
+            "# -array says 'this is where we were when we ended the array'\n");
+        printf("# skip says 'this is a structural or value I am skipping'\n");
+        printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
+        printf("#\n");
+        printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
+        printf("# in addition to the depth being displayed.\n");
+        printf("#\n");
+        printf("# Every token in the document has a single depth determined by the tokens before it,\n");
+        printf("# and is not affected by what the token actually is.\n");
+        printf("#\n");
+        printf("# Not all structural elements are presented as tokens in the logs.\n");
+        printf("#\n");
+        printf("# We never give control to the user within an empty array or an empty object.\n");
+        printf("#\n");
+        printf("# Inside an array, having a depth greater than the array's depth means that\n");
+        printf("# we are pointing inside a value.\n");
+        printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
+        printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
+        displayed_hint = true;
+      }
+      printf("\n");
+      printf("| %-*s ", LOG_EVENT_LEN, "Event");
+      printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
+      printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
+      // printf("| %-*s ", 5,                    "Next#");
+      printf("| %-*s ", 5, "Depth");
+      printf("| Detail ");
+      printf("|\n");
 
-  while (cur_struct_index <= static_cast<int64_t>(stream->parser->implementation->n_structural_indexes)) {
-    switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) {
-      case '{': case '[':
-        depth++;
-        break;
-      case '}': case ']':
-        depth--;
-        break;
+      printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
+      printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
+      printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
+      // printf("|%.*s", 5+2, DASHES);
+      printf("|%.*s", 5 + 2, DASHES);
+      printf("|--------");
+      printf("|\n");
+      fflush(stdout);
     }
-    if (depth == 0) { break; }
-    cur_struct_index++;
   }
-
-  return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);;
 }
 
-inline error_code document_stream::iterator::error() const noexcept {
-  return stream->error;
+template <typename... Args>
+inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
+  log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
 }
 
-#ifdef SIMDJSON_THREADS_ENABLED
-
-inline void document_stream::load_from_stage1_thread() noexcept {
-  worker->finish();
-  // Swap to the parser that was loaded up in the thread. Make sure the parser has
-  // enough memory to swap to, as well.
-  std::swap(stage1_thread_parser,*parser);
-  error = stage1_thread_error;
-  if (error) { return; }
-
-  // If there's anything left, start the stage 1 thread!
-  if (next_batch_start() < len) {
-    start_stage1_thread();
+template <typename... Args>
+inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
+  if (LOG_ENABLED) {
+    if (simdjson_unlikely(should_log(level))) {
+      const int indent = depth * 2;
+      const auto buf = iter.token.buf;
+      auto msg = string_format(title, std::forward<Args>(args)...);
+      printf("| %*s%s%-*s ", indent, "", title_prefix,
+             LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
+      {
+        // Print the current structural.
+        printf("| ");
+        // Before we begin, the index might point right before the document.
+        // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
+        if (index < iter._root) {
+          printf("%*s", LOG_BUFFER_LEN, "");
+        } else {
+          auto current_structural = &buf[*index];
+          for (int i = 0; i < LOG_BUFFER_LEN; i++) {
+            printf("%c", printable_char(current_structural[i]));
+          }
+        }
+        printf(" ");
+      }
+      {
+        // Print the next structural.
+        printf("| ");
+        auto next_structural = &buf[*(index + 1)];
+        for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
+          printf("%c", printable_char(next_structural[i]));
+        }
+        printf(" ");
+      }
+      // printf("| %5u ", *(index+1));
+      printf("| %5i ", depth);
+      printf("| %6.*s ", int(detail.size()), detail.data());
+      printf("|\n");
+      fflush(stdout);
+    }
   }
 }
 
-inline void document_stream::start_stage1_thread() noexcept {
-  // we call the thread on a lambda that will update
-  // this->stage1_thread_error
-  // there is only one thread that may write to this value
-  // TODO this is NOT exception-safe.
-  this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error
-  size_t _next_batch_start = this->next_batch_start();
-
-  worker->run(this, & this->stage1_thread_parser, _next_batch_start);
-}
-
-#endif // SIMDJSON_THREADS_ENABLED
-
+} // namespace logger
 } // namespace ondemand
 } // namespace lasx
 } // namespace simdjson
 
-namespace simdjson {
-
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(error)
-{
-}
-simdjson_inline simdjson_result<lasx::ondemand::document_stream>::simdjson_result(
-  lasx::ondemand::document_stream &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::document_stream>(
-      std::forward<lasx::ondemand::document_stream>(value)
-    )
-{
-}
-
-}
-
-#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H
-/* end file simdjson/generic/ondemand/document_stream-inl.h for lasx */
-/* including simdjson/generic/ondemand/field-inl.h for lasx: #include "simdjson/generic/ondemand/field-inl.h" */
-/* begin file simdjson/generic/ondemand/field-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
+/* end file simdjson/generic/ondemand/logger-inl.h for lasx */
+/* including simdjson/generic/ondemand/object-inl.h for lasx: #include "simdjson/generic/ondemand/object-inl.h" */
+/* begin file simdjson/generic/ondemand/object-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-// clang 6 does not think the default constructor can be noexcept, so we make it explicit
-simdjson_inline field::field() noexcept : std::pair<raw_json_string, ondemand::value>() {}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
+  return find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
+  return std::forward<object>(*this).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
+simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
+  bool has_value;
+  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
+  if (!has_value) {
+    logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
+    return NO_SUCH_FIELD;
+  }
+  return value(iter.child());
+}
 
-simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept
-  : std::pair<raw_json_string, ondemand::value>(key, std::forward<ondemand::value>(value))
-{
+simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_object().error() );
+  return object(iter);
+}
+simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.start_root_object().error() );
+  return object(iter);
+}
+simdjson_inline error_code object::consume() noexcept {
+  if(iter.is_at_key()) {
+    /**
+     * whenever you are pointing at a key, calling skip_child() is
+     * unsafe because you will hit a string and you will assume that
+     * it is string value, and this mistake will lead you to make bad
+     * depth computation.
+     */
+    /**
+     * We want to 'consume' the key. We could really
+     * just do _json_iter->return_current_and_advance(); at this
+     * point, but, for clarity, we will use the high-level API to
+     * eat the key. We assume that the compiler optimizes away
+     * most of the work.
+     */
+    simdjson_unused raw_json_string actual_key;
+    auto error = iter.field_key().get(actual_key);
+    if (error) { iter.abandon(); return error; };
+    // Let us move to the value while we are at it.
+    if ((error = iter.field_value())) { iter.abandon(); return error; }
+  }
+  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
+  if(error_skip) { iter.abandon(); }
+  return error_skip;
 }
 
-simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
-  raw_json_string key;
-  SIMDJSON_TRY( parent_iter.field_key().get(key) );
-  SIMDJSON_TRY( parent_iter.field_value() );
-  return field::start(parent_iter, key);
+simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
+  const uint8_t * starting_point{iter.peek_start()};
+  auto error = consume();
+  if(error) { return error; }
+  const uint8_t * final_point{iter._json_iter->peek()};
+  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
 }
 
-simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
-    return field(key, parent_iter.child());
+simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
+  SIMDJSON_TRY( iter.started_object().error() );
+  return object(iter);
 }
 
-simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
-  simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter(), allow_replacement);
-  first.consume();
-  return answer;
+simdjson_inline object object::resume(const value_iterator &iter) noexcept {
+  return iter;
 }
 
-template <typename string_type>
-simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept {
-  std::string_view key;
-  SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) );
-  receiver = key;
-  return SUCCESS;
+simdjson_inline object::object(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{
 }
 
-simdjson_inline raw_json_string field::key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return first;
+simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
+#endif
+  return object_iterator(iter);
+}
+simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
+  return object_iterator(iter);
 }
 
+inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
+  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
+  json_pointer = json_pointer.substr(1);
+  size_t slash = json_pointer.find('/');
+  std::string_view key = json_pointer.substr(0, slash);
+  // Grab the child with the given key
+  simdjson_result<value> child;
 
-simdjson_inline std::string_view field::key_raw_json_token() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  return std::string_view(reinterpret_cast<const char*>(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1);
+  // If there is an escape character in the key, unescape it and then get the child.
+  size_t escape = key.find('~');
+  if (escape != std::string_view::npos) {
+    // Unescape the key
+    std::string unescaped(key);
+    do {
+      switch (unescaped[escape+1]) {
+        case '0':
+          unescaped.replace(escape, 2, "~");
+          break;
+        case '1':
+          unescaped.replace(escape, 2, "/");
+          break;
+        default:
+          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
+      }
+      escape = unescaped.find('~', escape+1);
+    } while (escape != std::string::npos);
+    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
+  } else {
+    child = find_field(key);
+  }
+  if(child.error()) {
+    return child; // we do not continue if there was an error
+  }
+  // If there is a /, we have to recurse and look up more of the path
+  if (slash != std::string_view::npos) {
+    child = child.at_pointer(json_pointer.substr(slash));
+  }
+  return child;
 }
 
-simdjson_inline std::string_view field::escaped_key() const noexcept {
-  SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
-  auto end_quote = second.iter._json_iter->token.peek(-1);
-  while(*end_quote != '"') end_quote--;
-  return std::string_view(reinterpret_cast<const char*>(first.buf), end_quote - first.buf);
+inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
+  auto json_pointer = json_path_to_pointer_conversion(json_path);
+  if (json_pointer == "-1") {
+    return INVALID_JSON_POINTER;
+  }
+  return at_pointer(json_pointer);
 }
 
-simdjson_inline value &field::value() & noexcept {
-  return second;
+simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
+  size_t count{0};
+  // Important: we do not consume any of the values.
+  for(simdjson_unused auto v : *this) { count++; }
+  // The above loop will always succeed, but we want to report errors.
+  if(iter.error()) { return iter.error(); }
+  // We need to move back at the start because we expect users to iterate through
+  // the object after counting the number of elements.
+  iter.reset_object();
+  return count;
 }
 
-simdjson_inline value field::value() && noexcept {
-  return std::forward<field>(*this).second;
+simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
+  bool is_not_empty;
+  auto error = iter.reset_object().get(is_not_empty);
+  if(error) { return error; }
+  return !is_not_empty;
+}
+
+simdjson_inline simdjson_result<bool> object::reset() & noexcept {
+  return iter.reset_object();
 }
 
 } // namespace ondemand
@@ -128323,387 +120669,450 @@ simdjson_inline value field::value() && noexcept {
 
 namespace simdjson {
 
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  lasx::ondemand::field &&value
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(
-      std::forward<lasx::ondemand::field>(value)
-    )
-{
+simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(lasx::ondemand::object &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::object>(std::forward<lasx::ondemand::object>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::object>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::object>(error) {}
+
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::begin() noexcept {
+  if (error()) { return error(); }
+  return first.begin();
 }
-simdjson_inline simdjson_result<lasx::ondemand::field>::simdjson_result(
-  error_code error
-) noexcept :
-    implementation_simdjson_result_base<lasx::ondemand::field>(error)
-{
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> simdjson_result<lasx::ondemand::object>::end() noexcept {
+  if (error()) { return error(); }
+  return first.end();
 }
-
-simdjson_inline simdjson_result<lasx::ondemand::raw_json_string> simdjson_result<lasx::ondemand::field>::key() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
   if (error()) { return error(); }
-  return first.key();
+  return first.find_field_unordered(key);
 }
-
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::key_raw_json_token() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
   if (error()) { return error(); }
-  return first.key_raw_json_token();
+  return std::forward<lasx::ondemand::object>(first).find_field_unordered(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::operator[](std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::object>(first)[key];
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) & noexcept {
+  if (error()) { return error(); }
+  return first.find_field(key);
+}
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::find_field(std::string_view key) && noexcept {
+  if (error()) { return error(); }
+  return std::forward<lasx::ondemand::object>(first).find_field(key);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::escaped_key() noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
   if (error()) { return error(); }
-  return first.escaped_key();
+  return first.at_pointer(json_pointer);
 }
 
-simdjson_inline simdjson_result<std::string_view> simdjson_result<lasx::ondemand::field>::unescaped_key(bool allow_replacement) noexcept {
+simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::object>::at_path(
+    std::string_view json_path) noexcept {
+  if (error()) {
+    return error();
+  }
+  return first.at_path(json_path);
+}
+
+inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::reset() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(allow_replacement);
+  return first.reset();
 }
 
-template<typename string_type>
-simdjson_inline error_code simdjson_result<lasx::ondemand::field>::unescaped_key(string_type &receiver, bool allow_replacement) noexcept {
+inline simdjson_result<bool> simdjson_result<lasx::ondemand::object>::is_empty() noexcept {
   if (error()) { return error(); }
-  return first.unescaped_key(receiver, allow_replacement);
+  return first.is_empty();
 }
 
-simdjson_inline simdjson_result<lasx::ondemand::value> simdjson_result<lasx::ondemand::field>::value() noexcept {
+simdjson_inline  simdjson_result<size_t> simdjson_result<lasx::ondemand::object>::count_fields() & noexcept {
   if (error()) { return error(); }
-  return std::move(first.value());
+  return first.count_fields();
 }
 
+simdjson_inline  simdjson_result<std::string_view> simdjson_result<lasx::ondemand::object>::raw_json() noexcept {
+  if (error()) { return error(); }
+  return first.raw_json();
+}
 } // namespace simdjson
 
-#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H
-/* end file simdjson/generic/ondemand/field-inl.h for lasx */
-/* including simdjson/generic/ondemand/json_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/json_iterator-inl.h" */
-/* begin file simdjson/generic/ondemand/json_iterator-inl.h for lasx */
-#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
+/* end file simdjson/generic/ondemand/object-inl.h for lasx */
+/* including simdjson/generic/ondemand/object_iterator-inl.h for lasx: #include "simdjson/generic/ondemand/object_iterator-inl.h" */
+/* begin file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
 
 /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
-/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */
-/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */
 /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */
-/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */
 /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
 namespace simdjson {
 namespace lasx {
 namespace ondemand {
 
-simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
-  : token(std::forward<token_iterator>(other.token)),
-    parser{other.parser},
-    _string_buf_loc{other._string_buf_loc},
-    error{other.error},
-    _depth{other._depth},
-    _root{other._root},
-    _streaming{other._streaming}
+//
+// object_iterator
+//
+
+simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
+  : iter{_iter}
+{}
+
+simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
+  error_code error = iter.error();
+  if (error) { iter.abandon(); return error; }
+  auto result = field::start(iter);
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (result.error()) { iter.abandon(); }
+  return result;
+}
+simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
+  return !(*this != other);
+}
+simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
+  return iter.is_open();
+}
+
+SIMDJSON_PUSH_DISABLE_WARNINGS
+SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+simdjson_inline object_iterator &object_iterator::operator++() noexcept {
+  // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
+  // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
+  if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
+
+  simdjson_unused error_code error;
+  if ((error = iter.skip_child() )) { return *this; }
+
+  simdjson_unused bool has_value;
+  if ((error = iter.has_next_field().get(has_value) )) { return *this; };
+  return *this;
+}
+SIMDJSON_POP_DISABLE_WARNINGS
+
+//
+// ### Live States
+//
+// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
+// always SUCCESS:
+//
+// - Start: This is the state when the object is first found and the iterator is just past the {.
+//   In this state, at_start == true.
+// - Next: After we hand a scalar value to the user, or an array/object which they then fully
+//   iterate over, the iterator is at the , or } before the next value. In this state,
+//   depth == iter.depth, at_start == false, and error == SUCCESS.
+// - Unfinished Business: When we hand an array/object to the user which they do not fully
+//   iterate over, we need to finish that iteration by skipping child values until we reach the
+//   Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
+//
+// ## Error States
+//
+// In error states, we will yield exactly one more value before stopping. iter.depth == depth
+// and at_start is always false. We decrement after yielding the error, moving to the Finished
+// state.
+//
+// - Chained Error: When the object iterator is part of an error chain--for example, in
+//   `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
+//   object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
+//   iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
+// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
+//   we flag that as an error and treat it exactly the same as a Chained Error. In this state,
+//   error == TAPE_ERROR, iter.depth == depth, and at_start == false.
+//
+// Errors that occur while reading a field to give to the user (such as when the key is not a
+// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
+// moving to the Finished state without transitioning through an Error state at all.
+//
+// ## Terminal State
+//
+// The terminal state has iter.depth < depth. at_start is always false.
+//
+// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
+//   In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
+//
+
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
+
+namespace simdjson {
+
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(
+  lasx::ondemand::object_iterator &&value
+) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>(std::forward<lasx::ondemand::object_iterator>(value))
 {
-  other.parser = nullptr;
+  first.iter.assert_is_valid();
 }
-simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
-  token = other.token;
-  parser = other.parser;
-  _string_buf_loc = other._string_buf_loc;
-  error = other.error;
-  _depth = other._depth;
-  _root = other._root;
-  _streaming = other._streaming;
-  other.parser = nullptr;
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
+  : implementation_simdjson_result_base<lasx::ondemand::object_iterator>({}, error)
+{
+}
+
+simdjson_inline simdjson_result<lasx::ondemand::field> simdjson_result<lasx::ondemand::object_iterator>::operator*() noexcept {
+  if (error()) { return error(); }
+  return *first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator==(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return !error(); }
+  return first == other.first;
+}
+// If we're iterating and there is an error, return the error once.
+simdjson_inline bool simdjson_result<lasx::ondemand::object_iterator>::operator!=(const simdjson_result<lasx::ondemand::object_iterator> &other) const noexcept {
+  if (!first.iter.is_valid()) { return error(); }
+  return first != other.first;
+}
+// Checks for ']' and ','
+simdjson_inline simdjson_result<lasx::ondemand::object_iterator> &simdjson_result<lasx::ondemand::object_iterator>::operator++() noexcept {
+  // Clear the error if there is one, so we don't yield it twice
+  if (error()) { second = SUCCESS; return *this; }
+  ++first;
   return *this;
 }
 
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
-  : token(buf, &_parser->implementation->structural_indexes[0]),
-    parser{_parser},
-    _string_buf_loc{parser->string_buf.get()},
-    _depth{1},
-    _root{parser->implementation->structural_indexes.get()},
-    _streaming{false}
+} // namespace simdjson
+
+#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H
+/* end file simdjson/generic/ondemand/object_iterator-inl.h for lasx */
+/* including simdjson/generic/ondemand/parser-inl.h for lasx: #include "simdjson/generic/ondemand/parser-inl.h" */
+/* begin file simdjson/generic/ondemand/parser-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif
+namespace simdjson {
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline parser::parser(size_t max_capacity) noexcept
+  : _max_capacity{max_capacity} {
 }
 
-#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
-    : token(buf, &_parser->implementation->structural_indexes[0]),
-      parser{_parser},
-      _string_buf_loc{parser->string_buf.get()},
-      _depth{1},
-      _root{parser->implementation->structural_indexes.get()},
-      _streaming{streaming}
+simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
+  if (new_capacity > max_capacity()) { return CAPACITY; }
+  if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
 
-{
-  logger::log_headers();
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
+  // string_capacity copied from document::allocate
+  _capacity = 0;
+  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
+  string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
+#if SIMDJSON_DEVELOPMENT_CHECKS
+  start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
 #endif
+  if (implementation) {
+    SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
+    SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
+  } else {
+    SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
+  }
+  _capacity = new_capacity;
+  _max_depth = new_max_depth;
+  return SUCCESS;
 }
-#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
-
-inline void json_iterator::rewind() noexcept {
-  token.set_position( root_position() );
-  logger::log_headers(); // We start again
-  _string_buf_loc = parser->string_buf.get();
-  _depth = 1;
+#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
+  return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
 }
+#endif
 
-inline bool json_iterator::balanced() const noexcept {
-  token_iterator ti(token);
-  int32_t count{0};
-  ti.set_position( root_position() );
-  while(ti.peek() <= peek_last()) {
-    switch (*ti.return_current_and_advance())
-    {
-    case '[': case '{':
-      count++;
-      break;
-    case ']': case '}':
-      count--;
-      break;
-    default:
-      break;
-    }
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
-  return count == 0;
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
 }
 
+#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
 
-// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
-// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
-// skip_child() function is not marked inline).
-SIMDJSON_PUSH_DISABLE_WARNINGS
-SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
-simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
-  if (depth() <= parent_depth) { return SUCCESS; }
-  switch (*return_current_and_advance()) {
-    // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-    // *missing* braces, then future lookups are not in the object/arrays they think they are,
-    // violating the rule "validate enough structure that the user can be confident they are
-    // looking at the right values."
-    // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
+  json.remove_utf8_bom();
 
-    // For the first open array/object in a value, we've already incremented depth, so keep it the same
-    // We never stop at colon, but if we did, it wouldn't affect depth
-    case '[': case '{': case ':':
-      logger::log_start_value(*this, "skip");
-      break;
-    // If there is a comma, we have just finished a value in an array/object, and need to get back in
-    case ',':
-      logger::log_value(*this, "skip");
-      break;
-    // ] or } means we just finished a value and need to jump out of the array/object
-    case ']': case '}':
-      logger::log_end_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-#if SIMDJSON_CHECK_EOF
-      // If there are no more tokens, the parent is incomplete.
-      if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
-#endif // SIMDJSON_CHECK_EOF
-      break;
-    case '"':
-      if(*peek() == ':') {
-        // We are at a key!!!
-        // This might happen if you just started an object and you skip it immediately.
-        // Performance note: it would be nice to get rid of this check as it is somewhat
-        // expensive.
-        // https://github.com/simdjson/simdjson/issues/1742
-        logger::log_value(*this, "key");
-        return_current_and_advance(); // eat up the ':'
-        break; // important!!!
-      }
-      simdjson_fallthrough;
-    // Anything else must be a scalar value
-    default:
-      // For the first scalar, we will have incremented depth already, so we decrement it here.
-      logger::log_value(*this, "skip");
-      _depth--;
-      if (depth() <= parent_depth) { return SUCCESS; }
-      break;
+  // Allocate if needed
+  if (capacity() < json.length() || !string_buf) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
   }
 
-  // Now that we've considered the first value, we only increment/decrement for arrays/objects
-  while (position() < end_position()) {
-    switch (*return_current_and_advance()) {
-      case '[': case '{':
-        logger::log_start_value(*this, "skip");
-        _depth++;
-        break;
-      // TODO consider whether matching braces is a requirement: if non-matching braces indicates
-      // *missing* braces, then future lookups are not in the object/arrays they think they are,
-      // violating the rule "validate enough structure that the user can be confident they are
-      // looking at the right values."
-      // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
-      case ']': case '}':
-        logger::log_end_value(*this, "skip");
-        _depth--;
-        if (depth() <= parent_depth) { return SUCCESS; }
-        break;
-      default:
-        logger::log_value(*this, "skip", "");
-        break;
-    }
+  // Run stage 1.
+  const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
+  if (err) {
+    if (err != UNCLOSED_STRING)
+      return err;
   }
-
-  return report_error(TAPE_ERROR, "not enough close braces");
+  return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
 }
+#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
 
-SIMDJSON_POP_DISABLE_WARNINGS
-
-simdjson_inline bool json_iterator::at_root() const noexcept {
-  return position() == root_position();
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-simdjson_inline bool json_iterator::is_single_token() const noexcept {
-  return parser->implementation->n_structural_indexes == 1;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, len, allocated));
 }
 
-simdjson_inline bool json_iterator::streaming() const noexcept {
-  return _streaming;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
+  return iterate(padded_string_view(json, allocated));
 }
 
-simdjson_inline token_position json_iterator::root_position() const noexcept {
-  return _root;
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
+  if(json.capacity() - json.size() < SIMDJSON_PADDING) {
+    json.reserve(json.size() + SIMDJSON_PADDING);
+  }
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
+  return iterate(padded_string_view(json));
 }
 
-simdjson_inline void json_iterator::assert_at_root() const noexcept {
-  SIMDJSON_ASSUME( _depth == 1 );
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
-  // has side effects that will be discarded.
-  SIMDJSON_ASSUME( token.position() == _root );
-#endif
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  padded_string_view json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
-  assert_valid_position(token._position + required_tokens - 1);
+simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
+  // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
+  SIMDJSON_TRY( result.error() );
+  const padded_string &json = result.value_unsafe();
+  return iterate(json);
 }
 
-simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
-  SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
-#endif
+simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
+  if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
+
+  json.remove_utf8_bom();
+
+  // Allocate if needed
+  if (capacity() < json.length()) {
+    SIMDJSON_TRY( allocate(json.length(), max_depth()) );
+  }
+
+  // Run stage 1.
+  SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
+  return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
 }
 
-simdjson_inline bool json_iterator::at_end() const noexcept {
-  return position() == end_position();
+inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+  if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
+    buf += 3;
+    len -= 3;
+  }
+  if(allow_comma_separated && batch_size < len) { batch_size = len; }
+  return document_stream(*this, buf, len, batch_size, allow_comma_separated);
 }
-simdjson_inline token_position json_iterator::end_position() const noexcept {
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  return &parser->implementation->structural_indexes[n_structural_indexes];
+inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
+}
+inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
+  return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
 }
 
-inline std::string json_iterator::to_string() const noexcept {
-  if( !is_alive() ) { return "dead json_iterator instance"; }
-  const char * current_structural = reinterpret_cast<const char *>(token.peek());
-  return std::string("json_iterator [ depth : ") + std::to_string(_depth)
-          + std::string(", structural : '") + std::string(current_structural,1)
-          + std::string("', offset : ") + std::to_string(token.current_offset())
-          + std::string("', error : ") + error_message(error)
-          + std::string(" ]");
+simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
+  return _capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
+  return _max_capacity;
+}
+simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
+  return _max_depth;
 }
 
-inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
-  if (!is_alive()) {    // Unrecoverable error
-    if (!at_root()) {
-      return reinterpret_cast<const char *>(token.peek(-1));
-    } else {
-      return reinterpret_cast<const char *>(token.peek());
-    }
-  }
-  if (at_end()) {
-    return OUT_OF_BOUNDS;
+simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
+  if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
+    _max_capacity = max_capacity;
+  } else {
+    _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
   }
-  return reinterpret_cast<const char *>(token.peek());
 }
 
-simdjson_inline bool json_iterator::is_alive() const noexcept {
-  return parser;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
+  uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-simdjson_inline void json_iterator::abandon() noexcept {
-  parser = nullptr;
-  _depth = 0;
+simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
+  uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
+  if (!end) { return STRING_ERROR; }
+  std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
+  dst = end;
+  return result;
 }
 
-simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens();
-#endif // SIMDJSON_CHECK_EOF
-  return token.return_current_and_advance();
-}
+} // namespace ondemand
+} // namespace lasx
+} // namespace simdjson
 
-simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
-  // deliberately done without safety guard:
-  return token.peek();
-}
+namespace simdjson {
 
-simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek(delta);
-}
+simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(lasx::ondemand::parser &&value) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::parser>(std::forward<lasx::ondemand::parser>(value)) {}
+simdjson_inline simdjson_result<lasx::ondemand::parser>::simdjson_result(error_code error) noexcept
+    : implementation_simdjson_result_base<lasx::ondemand::parser>(error) {}
 
-simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_more_tokens(delta+1);
-#endif // #if SIMDJSON_CHECK_EOF
-  return token.peek_length(delta);
-}
+} // namespace simdjson
 
-simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
-  // todo: currently we require end-of-string buffering, but the following
-  // assert_valid_position should be turned on if/when we lift that condition.
-  // assert_valid_position(position);
-  // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
-  // is ON by default, we have no choice but to disable it for real with a comment.
-  return token.peek(position);
-}
+#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
+/* end file simdjson/generic/ondemand/parser-inl.h for lasx */
+/* including simdjson/generic/ondemand/raw_json_string-inl.h for lasx: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */
+/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for lasx */
+#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H
 
-simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_length(position);
-}
-simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept {
-#if SIMDJSON_CHECK_EOF
-  assert_valid_position(position);
-#endif // SIMDJSON_CHECK_EOF
-  return token.peek_root_length(position);
-}
+/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
+/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */
+/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */
+/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */
 
-simdjson_inline token_position json_iterator::last_position() const noexcept {
-  // The following line fails under some compilers...
-  // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
-  // since it has side-effects.
-  uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
-  SIMDJSON_ASSUME(n_structural_indexes > 0);
-  return &parser->implementation->structural_indexes[n_structural_indexes - 1];
-}
-simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
-  return token.peek(last_position());
-}
+namespace simdjson {
+
+namespace lasx {
+namespace ondemand {
+
+simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
+
+simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
 
-simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
-  SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
-  SIMDJSON_ASSUME(_depth == parent_depth + 1);
-  _depth = parent_depth;
-}
 
 simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
   size_t pos{0};
@@ -128744,15 +121153,10 @@ simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* t
   return true;
 }
 
-simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
-  return _string_buf_loc;
-}
 
-simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
-  SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
-  logger::log_error(*this, message);
-  error = _error;
-  return error;
+simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
+  // If we are going to call memcmp, then we must know something about the length of the raw_json_string.
+  return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
 }
 
 simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
@@ -128770,57 +121174,77 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) c
   return true;
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape(in, _string_buf_loc, allow_replacement);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape(in, _string_buf_loc, allow_replacement);
-#endif
+simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;pos < target.size();pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
-#if SIMDJSON_DEVELOPMENT_CHECKS
-  auto result = parser->unescape_wobbly(in, _string_buf_loc);
-  SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc));
-  return result;
-#else
-  return parser->unescape_wobbly(in, _string_buf_loc);
-#endif
-}
 
-simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
-  SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
-  SIMDJSON_ASSUME(_depth == child_depth - 1);
-#if SIMDJSON_DEVELOPMENT_CHECKS
-#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
-  SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
-  SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
-#endif
-#endif
-  token.set_position(position);
-  _depth = child_depth;
+simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
+  // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+  }
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
-  if (*peek() == c) {
-    return_current_and_advance();
-    return SUCCESS;
+simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
+  // Assumptions: does not contain unescaped quote characters, and
+  // the raw content is quote terminated within a valid JSON string.
+  const char * r{raw()};
+  size_t pos{0};
+  bool escaping{false};
+  for(;target[pos];pos++) {
+    if(r[pos] != target[pos]) { return false; }
+    // if target is a compile-time constant and it is free from
+    // quotes, then the next part could get optimized away through
+    // inlining.
+    if((target[pos] == '"') && !escaping) {
+      // We have reached the end of the raw_json_string but
+      // the target is not done.
+      return false;
+    } else if(target[pos] == '\\') {
+      escaping = !escaping;
+    } else {
+      escaping = false;
+    }
   }
-  return TAPE_ERROR;
+  if(r[pos] != '"') { return false; }
+  return true;
 }
 
-#if SIMDJSON_DEVELOPMENT_CHECKS
+simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
+  return a.unsafe_is_equal(c);
+}
 
-simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
+simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
+  return a == c;
 }
 
-simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
-  SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
-  if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
+simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
+  return !(a == c);
 }
 
 simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {