diff --git a/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj b/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj
new file mode 100644
index 0000000..7b7ec5f
--- /dev/null
+++ b/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj
@@ -0,0 +1,184 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 18.0
+ Win32Proj
+ {93f0d716-a83d-4afd-af9d-4f947d1c9f02}
+ HarteTestZ80
+ 10.0
+
+
+
+ Application
+ true
+ v145
+ Unicode
+
+
+ Application
+ false
+ v145
+ true
+ Unicode
+
+
+ Application
+ true
+ v145
+ Unicode
+
+
+ Application
+ false
+ v145
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\inc;..\..\inc;C:\Libraries\boost_1_88_0;$(IncludePath)
+
+
+ ..\inc;..\..\inc;C:\Libraries\boost_1_88_0;$(IncludePath)
+
+
+ ..\inc;..\..\inc;C:\Libraries\boost_1_88_0;$(IncludePath)
+
+
+ ..\inc;..\..\inc;C:\Libraries\boost_1_88_0;$(IncludePath)
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {d8726a1b-bbfe-47ef-9860-26b90140ba66}
+
+
+ {a9c24bd9-0cb4-4c84-b09b-46b815f9da47}
+
+
+ {01974f81-2750-45af-b845-2c903a54a334}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj.filters b/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj.filters
new file mode 100644
index 0000000..0740e45
--- /dev/null
+++ b/Z80/HarteTest_Z80/HarteTest_Z80.vcxproj.filters
@@ -0,0 +1,92 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Z80/HarteTest_Z80/TestRunner.cpp b/Z80/HarteTest_Z80/TestRunner.cpp
new file mode 100644
index 0000000..14a0ccb
--- /dev/null
+++ b/Z80/HarteTest_Z80/TestRunner.cpp
@@ -0,0 +1,23 @@
+#include "stdafx.h"
+#include "TestRunner.h"
+
+TestRunner::TestRunner() {}
+
+EightBit::MemoryMapping TestRunner::mapping(const uint16_t address) noexcept {
+ return { RAM(), 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
+}
+
+void TestRunner::raisePOWER() noexcept {
+ EightBit::Bus::raisePOWER();
+ CPU().raisePOWER();
+ CPU().raiseRESET();
+ CPU().raiseINT();
+ CPU().raiseNMI();
+}
+
+void TestRunner::lowerPOWER() noexcept {
+ CPU().lowerPOWER();
+ EightBit::Bus::lowerPOWER();
+}
+
+void TestRunner::initialise() {}
diff --git a/Z80/HarteTest_Z80/TestRunner.h b/Z80/HarteTest_Z80/TestRunner.h
new file mode 100644
index 0000000..0dea53e
--- /dev/null
+++ b/Z80/HarteTest_Z80/TestRunner.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+#include
+#include
+
+class TestRunner final : public EightBit::Bus {
+private:
+ EightBit::Ram m_ram = 0x10000;
+ EightBit::InputOutput m_ports;
+ EightBit::Z80 m_cpu = { *this, m_ports };
+
+protected:
+ EightBit::MemoryMapping mapping(uint16_t address) noexcept final;
+
+public:
+ TestRunner();
+
+ void raisePOWER() noexcept final;
+ void lowerPOWER() noexcept final;
+
+ void initialise() final;
+
+ [[nodiscard]] constexpr auto& RAM() noexcept { return m_ram; }
+ [[nodiscard]] constexpr auto& ports() noexcept { return m_ports; }
+ [[nodiscard]] constexpr auto& CPU() noexcept { return m_cpu; }
+};
diff --git a/Z80/HarteTest_Z80/array_t.h b/Z80/HarteTest_Z80/array_t.h
new file mode 100644
index 0000000..a4e583a
--- /dev/null
+++ b/Z80/HarteTest_Z80/array_t.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "simdjson/simdjson.h"
+
+class array_t {
+private:
+ const simdjson::dom::array m_raw;
+
+protected:
+ [[nodiscard]] simdjson::dom::array raw() const noexcept { return m_raw; }
+
+public:
+ [[nodiscard]] auto begin() const noexcept { return raw().begin(); }
+ [[nodiscard]] auto end() const noexcept { return raw().end(); }
+ [[nodiscard]] auto size() const noexcept { return raw().size(); }
+
+ [[nodiscard]] auto at(size_t idx) const noexcept { return raw().at(idx); }
+ [[nodiscard]] auto operator[](size_t idx) const noexcept { return at(idx); }
+
+protected:
+
+ [[nodiscard]] std::optional maybe_integer_at(size_t idx) const noexcept {
+ auto possible = at(idx);
+ if (possible.has_value() && possible.is_int64())
+ return std::optional(possible.get_int64());
+ return std::optional();
+ }
+
+ [[nodiscard]] std::optional maybe_string_at(size_t idx) const noexcept {
+ auto possible = at(idx);
+ if (possible.has_value() && possible.is_string())
+ return std::optional(possible.get_string());
+ return std::optional();
+ }
+
+ template
+ [[nodiscard]] auto maybe_cast_integer_at(size_t idx) const noexcept {
+ auto original = maybe_integer_at(idx);
+ if (original.has_value())
+ return std::optional(T(original.value()));
+ return std::optional();
+ }
+
+ [[nodiscard]] auto integer_at(size_t idx) const noexcept { return maybe_integer_at(idx).value(); }
+ [[nodiscard]] auto string_at(size_t idx) const noexcept { return maybe_string_at(idx).value(); }
+
+public:
+ array_t(const simdjson::dom::array input) noexcept
+ : m_raw(input) {}
+
+ [[nodiscard]] auto maybe_address_at(size_t idx) const noexcept {
+ return maybe_cast_integer_at(idx);
+ }
+
+ [[nodiscard]] auto maybe_byte_at(size_t idx) const noexcept {
+ return maybe_cast_integer_at(idx);
+ }
+
+ [[nodiscard]] auto address_at(size_t idx) const noexcept { return maybe_address_at(idx).value(); }
+ [[nodiscard]] auto byte_at(size_t idx) const noexcept { return maybe_byte_at(idx).value(); }
+};
diff --git a/Z80/HarteTest_Z80/byte_t.h b/Z80/HarteTest_Z80/byte_t.h
new file mode 100644
index 0000000..57597dc
--- /dev/null
+++ b/Z80/HarteTest_Z80/byte_t.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+
+#include "simdjson/simdjson.h"
+
+#include "array_t.h"
+
+class byte_t : public array_t {
+public:
+ byte_t(const simdjson::dom::array input) noexcept
+ : array_t(input) {}
+
+ [[nodiscard]] auto address() const noexcept { return address_at(0); }
+ [[nodiscard]] auto value() const noexcept { return byte_at(1); }
+};
diff --git a/Z80/HarteTest_Z80/checker_t.cpp b/Z80/HarteTest_Z80/checker_t.cpp
new file mode 100644
index 0000000..4c799e1
--- /dev/null
+++ b/Z80/HarteTest_Z80/checker_t.cpp
@@ -0,0 +1,384 @@
+#include "stdafx.h"
+#include "checker_t.h"
+#include "port_t.h"
+
+void checker_t::addActualCycle(const uint16_t address, const uint8_t value, const std::string& action) {
+ m_actualCycles.push_back({ address, value, action });
+}
+
+void checker_t::addActualCycle(const EightBit::register16_t address, const uint8_t value, const std::string& action) {
+ addActualCycle(address.word, value, action);
+}
+
+void checker_t::dumpCycles(const std::string which, const actual_cycles_t& events) {
+ m_messages.push_back(which);
+ dumpCycles(events);
+}
+
+void checker_t::dumpCycles(const actual_cycles_t& cycles) {
+ for (const auto& cycle : cycles)
+ dumpCycle(cycle);
+}
+
+void checker_t::dumpCycle(const actual_cycle_t& cycle) {
+ dumpCycle(std::get<0>(cycle), std::get<1>(cycle), std::get<2>(cycle));
+}
+
+void checker_t::dumpCycles(const std::string which, const cycles_t events) {
+ m_messages.push_back(which);
+ dumpCycles(events);
+}
+
+void checker_t::dumpCycles(const cycles_t cycles) {
+ for (const auto cycle : cycles)
+ dumpCycle(cycle_t(cycle));
+}
+
+void checker_t::dumpCycle(const cycle_t cycle) {
+ dumpCycle(cycle.address(), cycle.value(), cycle.action());
+}
+
+void checker_t::raise(const std::string& what, const uint16_t expected, const uint16_t actual) {
+ os()
+ << std::setw(2) << std::setfill(' ')
+ << what
+ << std::setw(4) << std::setfill('0')
+ << ": expected: " << (int)expected
+ << ", actual: " << (int)actual;
+ pushCurrentMessage();
+}
+
+void checker_t::raise(const std::string& what, const uint8_t expected, const uint8_t actual) {
+ os()
+ << std::setw(2) << std::setfill(' ')
+ << what
+ << std::setfill('0')
+ << ": expected: " << (int)expected
+ << ", actual: " << (int)actual;
+ pushCurrentMessage();
+}
+
+void checker_t::raiseFlags(const std::string& what, const uint8_t expected, const uint8_t actual) {
+ os()
+ << std::setw(2) << std::setfill(' ')
+ << what
+ << std::setfill('0')
+ << ": expected: " << EightBit::Disassembler::flags(expected)
+ << ", actual: " << EightBit::Disassembler::flags(actual);
+ pushCurrentMessage();
+}
+
+void checker_t::raise(const std::string& what, const std::string& expected, const std::string& actual) {
+ os()
+ << std::setw(0) << std::setfill(' ')
+ << what
+ << ": expected: " << expected
+ << ", actual: " << actual;
+ pushCurrentMessage();
+}
+
+bool checker_t::check(const std::string& what, const uint16_t address, const uint8_t expected, const uint8_t actual) {
+ const auto success = actual == expected;
+ if (!success) {
+ os() << what << ": " << std::setw(4) << std::setfill('0') << (int)address;
+ raise(os().str(), expected, actual);
+ }
+ return success;
+}
+
+checker_t::checker_t(TestRunner& runner)
+: m_runner(runner) {}
+
+void checker_t::initialiseState(test_t test) {
+ initialiseState(test.initial(), test.ports());
+}
+
+void checker_t::initialiseState(const state_t initial, std::optional ports) {
+
+ auto& cpu = runner().CPU();
+
+ cpu.PC() = initial.pc();
+ cpu.SP() = initial.sp();
+
+ // Alternate register set, then switch to the main set
+
+ cpu.AF() = initial.af_();
+ cpu.BC() = initial.bc_();
+ cpu.DE() = initial.de_();
+ cpu.HL() = initial.hl_();
+
+ cpu.exx();
+ cpu.exxAF();
+
+ // Now we're in the main register set, so set it up
+
+ cpu.AF() = { initial.f(), initial.a() };
+ cpu.BC() = { initial.c(), initial.b() };
+ cpu.DE() = { initial.e(), initial.d() };
+ cpu.HL() = { initial.l(), initial.h() };
+
+ // miscellaneous registers
+
+ cpu.IV() = initial.i();
+ cpu.REFRESH() = initial.r();
+
+ cpu.IM() = initial.im();
+
+ cpu.Q() = initial.q();
+
+ cpu.IFF1() = initial.iff1();
+ cpu.IFF2() = initial.iff2();
+
+ cpu.MEMPTR() = initial.wz();
+
+ cpu.IX() = initial.ix();
+ cpu.IY() = initial.iy();
+
+ auto& ram = runner().RAM();
+ for (const auto entry : initial.ram()) {
+ const byte_t byte{ entry };
+ const auto address = byte.address();
+ const auto value = byte.value();
+ ram.poke(address, value);
+ }
+
+ if (!ports.has_value())
+ return;
+
+ for (const auto entry : ports.value()) {
+ const port_t port{ entry };
+ const auto address = port.address();
+ const auto value = port.value();
+ const auto type = port.type();
+ if (type == "r") {
+ runner().ports().writeInputPort(address, value);
+ } else if (type == "w") {
+ runner().ports().writeOutputPort(address, value);
+ } else {
+ throw std::out_of_range("Unknown port state type");
+ }
+ }
+}
+
+void checker_t::initialise() {
+
+ auto& bus = runner();
+ auto& cpu = bus.CPU();
+ cpu.Ticked.connect([this](EightBit::EventArgs&) {
+
+ auto& bus = runner();
+ auto& cpu = bus.CPU();
+
+ const std::string read = EightBit::Device::lowered(cpu.RD()) ? "r" : "-";
+ const std::string write = EightBit::Device::lowered(cpu.WR()) ? "w" : "-";
+ const std::string memory = EightBit::Device::lowered(cpu.MREQ()) ? "m" : "-";
+ const std::string io = EightBit::Device::lowered(cpu.IORQ()) ? "i" : "-";
+
+ addActualCycle(bus.ADDRESS(), bus.DATA(), read + write + memory + io);
+ });
+
+ os() << std::hex << std::uppercase;
+}
+
+//
+bool checker_t::checkState(test_t test) {
+
+ auto& cpu = runner().CPU();
+ auto& ram = runner().RAM();
+
+ const auto& expected_cycles = test.cycles();
+ const auto& actual_cycles = m_actualCycles;
+
+ size_t actual_idx = 0;
+ for (const auto expected_cycle : expected_cycles) {
+
+ if (actual_idx >= actual_cycles.size()) {
+ m_cycle_count_mismatch = true;
+ return false; // more expected cycles than actual
+ }
+
+ const cycle_t expected{ expected_cycle };
+ const auto& actual = actual_cycles[actual_idx++];
+
+ const auto expected_address = expected.address();
+ const auto actual_address = std::get<0>(actual);
+ check("Cycle address", expected_address, actual_address);
+
+ const auto maybe_expected_value = expected.value();
+ if (maybe_expected_value.has_value()) {
+ const auto expected_value = maybe_expected_value.value();
+ const auto actual_value = std::get<1>(actual);
+ check("Cycle value", expected_value, actual_value);
+ }
+
+ const auto expected_action = expected.action();
+ const auto& actual_action = std::get<2>(actual);
+ check("Cycle action", std::string(expected_action), actual_action);
+ }
+
+ if (actual_idx < actual_cycles.size()) {
+ m_cycle_count_mismatch = true;
+ return false; // less expected cycles than actual
+ }
+
+ if (!m_messages.empty())
+ return false;
+
+ const auto final = test.final();
+
+ const auto pc_good = check("PC", final.pc(), cpu.PC().word);
+ const auto sp_good = check("SP", final.sp(), cpu.SP().word);
+
+ const auto a_good = check("A", final.a(), cpu.A());
+ const auto f_good = check("F", final.f(), cpu.F());
+ const auto af_good = a_good && f_good;
+
+ const auto b_good = check("B", final.b(), cpu.B());
+ const auto c_good = check("C", final.c(), cpu.C());
+ const auto bc_good = b_good && c_good;
+
+ const auto d_good = check("D", final.d(), cpu.D());
+ const auto e_good = check("E", final.e(), cpu.E());
+ const auto de_good = d_good && e_good;
+
+ const auto h_good = check("H", final.h(), cpu.H());
+ const auto l_good = check("L", final.l(), cpu.L());
+ const auto hl_good = h_good && l_good;
+
+ cpu.exxAF();
+ cpu.exx();
+
+ const auto af_alt_good = check("AF'", final.af_(), cpu.AF().word);
+ const auto bc_alt_good = check("BC'", final.bc_(), cpu.BC().word);
+ const auto de_alt_good = check("DE'", final.de_(), cpu.DE().word);
+ const auto hl_alt_good = check("DE'", final.de_(), cpu.DE().word);
+
+ const auto i_good = check("I", final.i(), cpu.IV());
+ const auto r_good = check("R", final.r(), (uint8_t)cpu.REFRESH());
+
+ const auto im_good = check("IM", final.im(), (uint8_t)cpu.IM());
+
+ const auto q_good = check("Q", final.im(), (uint8_t)cpu.IM());
+
+ const auto iff1_good = check("IFF1", final.iff1(), (uint8_t)cpu.IFF1());
+ const auto iff2_good = check("IFF2", final.iff2(), (uint8_t)cpu.IFF2());
+ const auto iff_good = iff1_good && iff2_good;
+
+ const auto memptr_good = check("MEMPTR", final.wz(), cpu.MEMPTR().word);
+
+ const auto ix_good = check("IX", final.ix(), cpu.IX().word);
+ const auto iy_good = check("IY", final.iy(), cpu.IY().word);
+
+ bool ram_problem = false;
+ for (const auto entry : final.ram()) {
+ const auto byte = byte_t{ entry };
+ const auto address = byte.address();
+ const auto value = byte.value();
+ if (!check("RAM", address, value, ram.peek(address)))
+ ram_problem = true;
+ }
+
+ return
+ pc_good && sp_good
+ && af_good && bc_good && de_good && hl_good
+ && af_alt_good && bc_alt_good && de_alt_good && hl_alt_good
+ && i_good && r_good
+ && im_good
+ && q_good
+ && iff_good
+ && memptr_good
+ && ix_good && iy_good
+ && !ram_problem;
+}
+//
+void checker_t::pushCurrentMessage() {
+ m_messages.push_back(os().str());
+ os().str("");
+}
+
+std::string checker_t::disassemble(uint16_t address) {
+ return m_disassembler.disassemble(runner().CPU(), address);
+}
+
+void checker_t::add_disassembly(uint16_t address) {
+ try {
+ os() << disassemble(address);
+ }
+ catch (const std::domain_error& error) {
+ os() << "Disassembly problem: " << error.what();
+ }
+ pushCurrentMessage();
+}
+
+void checker_t::check(test_t test) {
+
+ auto& cpu = runner().CPU();
+
+ m_messages.clear();
+ m_actualCycles.clear();
+
+ runner().raisePOWER();
+ initialiseState(test);
+ const auto pc = cpu.PC().word;
+
+ m_cycles = cpu.step();
+ runner().lowerPOWER();
+
+ m_valid = checkState(test);
+
+ if (unimplemented()) {
+ m_messages.push_back("Unimplemented");
+ return;
+ }
+
+ if (invalid() && implemented()) {
+
+ add_disassembly(pc);
+
+ const auto final = test.final();
+ raise("PC", final.pc(), cpu.PC().word);
+ raise("SP", final.sp(), cpu.SP().word);
+
+ raise("A", final.a(), cpu.A());
+ raiseFlags("F", final.a(), cpu.A());
+ raise("B", final.b(), cpu.B());
+ raise("C", final.c(), cpu.C());
+ raise("D", final.d(), cpu.D());
+ raise("E", final.e(), cpu.E());
+ raise("H", final.h(), cpu.H());
+ raise("L", final.l(), cpu.L());
+
+ cpu.exx();
+ cpu.exxAF();
+
+ raise("'AF", final.af_(), cpu.AF().word);
+ raise("'BC", final.bc_(), cpu.BC().word);
+ raise("'DE", final.de_(), cpu.DE().word);
+ raise("'HL", final.hl_(), cpu.HL().word);
+
+ raise("I", final.i(), cpu.IV());
+ raise("R", final.r(), cpu.REFRESH());
+
+ raise("IM", final.im(), (uint8_t)cpu.IM());
+
+ raise("Q", final.q(), cpu.Q());
+
+ raise("IFF1", final.iff1(), (uint8_t)cpu.IFF1());
+ raise("IFF2", final.iff2(), (uint8_t)cpu.IFF2());
+
+ raise("WZ", final.wz(), cpu.MEMPTR().word);
+
+ raise("IX", final.ix(), cpu.IX().word);
+ raise("IY", final.iy(), cpu.IY().word);
+
+ os()
+ << std::dec << std::setfill(' ')
+ << "Stepped cycles: " << cycles()
+ << ", expected events: " << test.cycles().size()
+ << ", actual events: " << m_actualCycles.size();
+ pushCurrentMessage();
+
+ dumpCycles("-- Expected cycles", test.cycles());
+ dumpCycles("-- Actual cycles", m_actualCycles);
+ }
+}
diff --git a/Z80/HarteTest_Z80/checker_t.h b/Z80/HarteTest_Z80/checker_t.h
new file mode 100644
index 0000000..55399b9
--- /dev/null
+++ b/Z80/HarteTest_Z80/checker_t.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+#include "cycles_t.h"
+#include "cycle_t.h"
+#include "test_t.h"
+
+#include "TestRunner.h"
+
+class checker_t {
+private:
+ TestRunner& m_runner;
+ EightBit::Disassembler m_disassembler = { m_runner };
+
+ std::ostringstream m_os;
+ std::vector m_messages;
+
+ typedef std::tuple actual_cycle_t;
+ typedef std::vector actual_cycles_t;
+ actual_cycles_t m_actualCycles;
+ bool m_cycle_count_mismatch = false;
+
+ int m_cycles = 0;
+ bool m_valid = true;
+
+ [[nodiscard]] constexpr auto& os() noexcept { return m_os; }
+
+ [[nodiscard]] constexpr auto& runner() noexcept { return m_runner; }
+
+ [[nodiscard]] bool checkState(test_t test);
+
+ void pushCurrentMessage();
+
+ void raise(const std::string& what, uint16_t expected, uint16_t actual);
+ void raise(const std::string& what, uint8_t expected, uint8_t actual);
+ void raiseFlags(const std::string& what, uint8_t expected, uint8_t actual);
+ void raise(const std::string& what, const std::string& expected, const std::string& actual);
+
+ template
+ constexpr bool check(const std::string& what, T expected, T actual) noexcept {
+ const auto success = actual == expected;
+ if (!success)
+ raise(what, expected, actual);
+ return success;
+ }
+
+ bool check(const std::string& what, uint16_t address, uint8_t expected, uint8_t actual);
+
+ void addActualCycle(uint16_t address, uint8_t value, const std::string& action);
+ void addActualCycle(EightBit::register16_t address, uint8_t value, const std::string& action);
+
+ void add_disassembly(uint16_t address);
+
+ template
+ void dumpCycle(const uint16_t address, const std::optional value, const T action) {
+ if (value.has_value())
+ m_os
+ << std::setfill('0') << std::hex
+ << "Address: " << std::setw(4) << (int)address
+ << ", value: " << std::setw(2) << (int)value.value()
+ << ", action: " << action;
+ else
+ m_os
+ << std::setfill('0') << std::hex
+ << "Address: " << std::setw(4) << (int)address
+ << " "
+ << ", action: " << action;
+ pushCurrentMessage();
+ }
+
+ void dumpCycles(std::string which, cycles_t cycles);
+ void dumpCycles(cycles_t cycles);
+ void dumpCycle(cycle_t cycle);
+
+ void dumpCycles(std::string which, const actual_cycles_t& cycles);
+ void dumpCycles(const actual_cycles_t& cycles);
+ void dumpCycle(const actual_cycle_t& cycle);
+
+ void initialiseState(test_t test);
+ void initialiseState(state_t state, std::optional ports);
+
+public:
+ checker_t(TestRunner& runner);
+
+ [[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }
+ [[nodiscard]] constexpr auto valid() const noexcept { return m_valid; }
+ [[nodiscard]] constexpr auto invalid() const noexcept { return !valid(); }
+ [[nodiscard]] constexpr auto unimplemented() const noexcept { return invalid() && m_cycle_count_mismatch && (cycles() == 1); }
+ [[nodiscard]] constexpr auto implemented() const noexcept { return !unimplemented(); }
+
+ [[nodiscard]] constexpr const auto& messages() const noexcept { return m_messages; }
+
+ void initialise();
+
+ [[nodiscard]] std::string disassemble(uint16_t address);
+
+ void check(test_t test);
+};
diff --git a/Z80/HarteTest_Z80/cycle_t.h b/Z80/HarteTest_Z80/cycle_t.h
new file mode 100644
index 0000000..6534e48
--- /dev/null
+++ b/Z80/HarteTest_Z80/cycle_t.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+#include "simdjson/simdjson.h"
+
+#include "byte_t.h"
+
+class cycle_t final : public array_t {
+public:
+ cycle_t(const simdjson::dom::array input) noexcept
+ : array_t(input) {}
+
+ [[nodiscard]] auto address() const noexcept { return address_at(0); }
+ [[nodiscard]] auto value() const noexcept { return maybe_byte_at(1); }
+ [[nodiscard]] auto action() const noexcept { return string_at(2); }
+};
diff --git a/Z80/HarteTest_Z80/cycles_t.h b/Z80/HarteTest_Z80/cycles_t.h
new file mode 100644
index 0000000..8172cc0
--- /dev/null
+++ b/Z80/HarteTest_Z80/cycles_t.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "array_t.h"
+
+typedef array_t cycles_t; // Intended to indicate that cycles_t is meant to hold cycle_t objects
diff --git a/Z80/HarteTest_Z80/element_t.h b/Z80/HarteTest_Z80/element_t.h
new file mode 100644
index 0000000..85fe5d4
--- /dev/null
+++ b/Z80/HarteTest_Z80/element_t.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+#include "simdjson/simdjson.h"
+
+class element_t {
+private:
+ simdjson::dom::element m_raw;
+
+protected:
+ [[nodiscard]] auto raw() const noexcept { return m_raw; }
+
+public:
+ element_t() noexcept {}
+
+ element_t(const simdjson::dom::element input) noexcept
+ : m_raw(input) {}
+
+ [[nodiscard]] auto at(std::string_view key) const noexcept { return raw()[key]; }
+ [[nodiscard]] auto operator[](std::string_view key) const noexcept { return at(key); }
+ [[nodiscard]] auto array_at(std::string_view key) const noexcept { return at(key).get_array(); }
+ [[nodiscard]] auto integer_at(std::string_view key) const noexcept { return int64_t(at(key)); }
+};
diff --git a/Z80/HarteTest_Z80/opcode_test_suite_t.cpp b/Z80/HarteTest_Z80/opcode_test_suite_t.cpp
new file mode 100644
index 0000000..764a3c8
--- /dev/null
+++ b/Z80/HarteTest_Z80/opcode_test_suite_t.cpp
@@ -0,0 +1,10 @@
+#include "stdafx.h"
+#include "opcode_test_suite_t.h"
+
+opcode_test_suite_t::opcode_test_suite_t(const std::string path) noexcept
+: parser_t(path) {}
+
+EightBit::co_generator_t opcode_test_suite_t::generator() const {
+ for (const auto element : *this)
+ co_yield test_t(element);
+}
\ No newline at end of file
diff --git a/Z80/HarteTest_Z80/opcode_test_suite_t.h b/Z80/HarteTest_Z80/opcode_test_suite_t.h
new file mode 100644
index 0000000..37ef000
--- /dev/null
+++ b/Z80/HarteTest_Z80/opcode_test_suite_t.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+#include
+
+#include "parser_t.h"
+#include "test_t.h"
+
+class opcode_test_suite_t final : public parser_t {
+private:
+ [[nodiscard]] auto array() const noexcept { return raw().get_array(); }
+
+public:
+ opcode_test_suite_t() noexcept {}
+ opcode_test_suite_t(std::string path) noexcept;
+
+ [[nodiscard]] auto begin() const noexcept { return array().begin(); }
+ [[nodiscard]] auto end() const noexcept { return array().end(); }
+ [[nodiscard]] auto size() const noexcept { return array().size(); }
+
+ [[nodiscard]] EightBit::co_generator_t generator() const;
+};
diff --git a/Z80/HarteTest_Z80/parser_t.cpp b/Z80/HarteTest_Z80/parser_t.cpp
new file mode 100644
index 0000000..c252248
--- /dev/null
+++ b/Z80/HarteTest_Z80/parser_t.cpp
@@ -0,0 +1,11 @@
+#include "stdafx.h"
+#include "parser_t.h"
+
+simdjson::dom::parser parser_t::m_parser;
+
+parser_t::parser_t(const std::string path) noexcept
+: m_path(path) {}
+
+void parser_t::load() {
+ m_raw = m_parser.load(m_path);
+}
diff --git a/Z80/HarteTest_Z80/parser_t.h b/Z80/HarteTest_Z80/parser_t.h
new file mode 100644
index 0000000..8a383ba
--- /dev/null
+++ b/Z80/HarteTest_Z80/parser_t.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+#include
+
+#include "simdjson/simdjson.h"
+
+class parser_t {
+private:
+ // N.B.
+ // The parser must be kept for the lifetime of any parsed data.
+ // Therefore, it can only be used for one document at a time.
+ static simdjson::dom::parser m_parser;
+
+ std::string m_path;
+ simdjson::dom::element m_raw;
+
+public:
+ parser_t() noexcept {}
+ parser_t(std::string path) noexcept;
+
+ [[nodiscard]] constexpr std::string_view path() const noexcept { return m_path; }
+ [[nodiscard]] const auto raw() const noexcept { return m_raw; }
+
+ virtual void load();
+};
diff --git a/Z80/HarteTest_Z80/port_t.h b/Z80/HarteTest_Z80/port_t.h
new file mode 100644
index 0000000..c2c860f
--- /dev/null
+++ b/Z80/HarteTest_Z80/port_t.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include
+
+#include "simdjson/simdjson.h"
+
+#include "byte_t.h"
+
+class port_t : public byte_t {
+public:
+ port_t(const simdjson::dom::array input) noexcept
+ : byte_t(input) {}
+
+ [[nodiscard]] auto type() const noexcept { return string_at(2); }
+};
diff --git a/Z80/HarteTest_Z80/ports_t.h b/Z80/HarteTest_Z80/ports_t.h
new file mode 100644
index 0000000..609943e
--- /dev/null
+++ b/Z80/HarteTest_Z80/ports_t.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "array_t.h"
+
+typedef array_t ports_t; // Intended to indicate that ports_t is meant to hold port_t objects
diff --git a/Z80/HarteTest_Z80/processor_test_suite_t.cpp b/Z80/HarteTest_Z80/processor_test_suite_t.cpp
new file mode 100644
index 0000000..f39672f
--- /dev/null
+++ b/Z80/HarteTest_Z80/processor_test_suite_t.cpp
@@ -0,0 +1,14 @@
+#include "stdafx.h"
+#include "processor_test_suite_t.h"
+
+#include
+
+processor_test_suite_t::processor_test_suite_t(std::string location) noexcept
+: m_location(location) {
+}
+
+EightBit::co_generator_t processor_test_suite_t::generator() const {
+ std::filesystem::path directory = location();
+ for (const auto& entry : std::filesystem::directory_iterator{ directory })
+ co_yield opcode_test_suite_t(entry.path().string());
+}
diff --git a/Z80/HarteTest_Z80/processor_test_suite_t.h b/Z80/HarteTest_Z80/processor_test_suite_t.h
new file mode 100644
index 0000000..3ca2179
--- /dev/null
+++ b/Z80/HarteTest_Z80/processor_test_suite_t.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+#include "opcode_test_suite_t.h"
+
+class processor_test_suite_t final {
+private:
+ std::string m_location;
+
+public:
+ processor_test_suite_t(std::string location) noexcept;
+
+ [[nodiscard]] constexpr std::string_view location() const noexcept { return m_location; }
+
+ [[nodiscard]] EightBit::co_generator_t generator() const;
+};
diff --git a/Z80/HarteTest_Z80/ram_t.h b/Z80/HarteTest_Z80/ram_t.h
new file mode 100644
index 0000000..f25e202
--- /dev/null
+++ b/Z80/HarteTest_Z80/ram_t.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "array_t.h"
+
+typedef array_t ram_t; // Intended to indicate that ram_t is meant to hold byte_t objects
diff --git a/Z80/HarteTest_Z80/simdjson/simdjson.cpp b/Z80/HarteTest_Z80/simdjson/simdjson.cpp
new file mode 100644
index 0000000..0374b89
--- /dev/null
+++ b/Z80/HarteTest_Z80/simdjson/simdjson.cpp
@@ -0,0 +1,65003 @@
+/* auto-generated on 2026-02-20 16:16:37 -0500. version 4.3.1 Do not edit! */
+/* including simdjson.cpp: */
+/* begin file simdjson.cpp */
+#define SIMDJSON_SRC_SIMDJSON_CPP
+
+/* including base.h: #include */
+/* begin file base.h */
+#ifndef SIMDJSON_SRC_BASE_H
+#define SIMDJSON_SRC_BASE_H
+
+/* including simdjson/base.h: #include */
+/* begin file simdjson/base.h */
+/**
+ * @file Base declarations for all simdjson headers
+ * @private
+ */
+#ifndef SIMDJSON_BASE_H
+#define SIMDJSON_BASE_H
+
+/* including simdjson/common_defs.h: #include "simdjson/common_defs.h" */
+/* begin file simdjson/common_defs.h */
+#ifndef SIMDJSON_COMMON_DEFS_H
+#define SIMDJSON_COMMON_DEFS_H
+
+#include
+/* including simdjson/compiler_check.h: #include "simdjson/compiler_check.h" */
+/* begin file simdjson/compiler_check.h */
+#ifndef SIMDJSON_COMPILER_CHECK_H
+#define SIMDJSON_COMPILER_CHECK_H
+
+#ifndef __cplusplus
+#error simdjson requires a C++ compiler
+#endif
+
+#ifndef SIMDJSON_CPLUSPLUS
+#if defined(_MSVC_LANG) && !defined(__clang__)
+#define SIMDJSON_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
+#else
+#define SIMDJSON_CPLUSPLUS __cplusplus
+#endif
+#endif
+
+// C++ 26
+#if !defined(SIMDJSON_CPLUSPLUS26) && (SIMDJSON_CPLUSPLUS >= 202402L) // update when the standard is finalized
+#define SIMDJSON_CPLUSPLUS26 1
+#endif
+
+// C++ 23
+#if !defined(SIMDJSON_CPLUSPLUS23) && (SIMDJSON_CPLUSPLUS >= 202302L)
+#define SIMDJSON_CPLUSPLUS23 1
+#endif
+
+// C++ 20
+#if !defined(SIMDJSON_CPLUSPLUS20) && (SIMDJSON_CPLUSPLUS >= 202002L)
+#define SIMDJSON_CPLUSPLUS20 1
+#endif
+
+// C++ 17
+#if !defined(SIMDJSON_CPLUSPLUS17) && (SIMDJSON_CPLUSPLUS >= 201703L)
+#define SIMDJSON_CPLUSPLUS17 1
+#endif
+
+// C++ 14
+#if !defined(SIMDJSON_CPLUSPLUS14) && (SIMDJSON_CPLUSPLUS >= 201402L)
+#define SIMDJSON_CPLUSPLUS14 1
+#endif
+
+// C++ 11
+#if !defined(SIMDJSON_CPLUSPLUS11) && (SIMDJSON_CPLUSPLUS >= 201103L)
+#define SIMDJSON_CPLUSPLUS11 1
+#endif
+
+#ifndef SIMDJSON_CPLUSPLUS11
+#error simdjson requires a compiler compliant with the C++11 standard
+#endif
+
+#ifndef SIMDJSON_IF_CONSTEXPR
+#if SIMDJSON_CPLUSPLUS17
+#define SIMDJSON_IF_CONSTEXPR if constexpr
+#else
+#define SIMDJSON_IF_CONSTEXPR if
+#endif
+#endif
+
+#ifndef SIMDJSON_CONSTEXPR_LAMBDA
+#if SIMDJSON_CPLUSPLUS17
+#define SIMDJSON_CONSTEXPR_LAMBDA constexpr
+#else
+#define SIMDJSON_CONSTEXPR_LAMBDA
+#endif
+#endif
+
+
+
+#ifdef __has_include
+#if __has_include()
+#include
+#endif
+#endif
+
+// The current specification is unclear on how we detect
+// static reflection, both __cpp_lib_reflection and
+// __cpp_impl_reflection are proposed in the draft specification.
+// For now, we disable static reflect by default. It must be
+// specified at compiler time.
+#ifndef SIMDJSON_STATIC_REFLECTION
+#define SIMDJSON_STATIC_REFLECTION 0 // disabled by default.
+#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_lib_ranges) && __cpp_lib_ranges >= 201911L
+#include
+#define SIMDJSON_SUPPORTS_RANGES 1
+#else
+#define SIMDJSON_SUPPORTS_RANGES 0
+#endif
+
+#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#if __cpp_concepts >= 201907L
+#include
+#define SIMDJSON_SUPPORTS_CONCEPTS 1
+#else
+#define SIMDJSON_SUPPORTS_CONCEPTS 0
+#endif
+#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+#define SIMDJSON_SUPPORTS_CONCEPTS 0
+#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
+
+// copy SIMDJSON_SUPPORTS_CONCEPTS to SIMDJSON_SUPPORTS_DESERIALIZATION.
+#if SIMDJSON_SUPPORTS_CONCEPTS
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
+#else
+#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
+#endif
+
+
+#if !defined(SIMDJSON_CONSTEVAL)
+#if defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
+#define SIMDJSON_CONSTEVAL 1
+#else
+#define SIMDJSON_CONSTEVAL 0
+#endif // defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
+#endif // !defined(SIMDJSON_CONSTEVAL)
+
+#endif // SIMDJSON_COMPILER_CHECK_H
+/* end file simdjson/compiler_check.h */
+/* including simdjson/portability.h: #include "simdjson/portability.h" */
+/* begin file simdjson/portability.h */
+#ifndef SIMDJSON_PORTABILITY_H
+#define SIMDJSON_PORTABILITY_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#ifndef _WIN32
+// strcasecmp, strncasecmp
+#include
+#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;
+
+#ifdef _MSC_VER
+#define SIMDJSON_VISUAL_STUDIO 1
+/**
+ * We want to differentiate carefully between
+ * clang under visual studio and regular visual
+ * studio.
+ *
+ * Under clang for Windows, we enable:
+ * * target pragmas so that part and only part of the
+ * code gets compiled for advanced instructions.
+ *
+ */
+#ifdef __clang__
+// clang under visual studio
+#define SIMDJSON_CLANG_VISUAL_STUDIO 1
+#else
+// just regular visual studio (best guess)
+#define SIMDJSON_REGULAR_VISUAL_STUDIO 1
+#endif // __clang__
+#endif // _MSC_VER
+
+#if (defined(__x86_64__) || defined(_M_AMD64)) && !defined(_M_ARM64EC)
+#define SIMDJSON_IS_X86_64 1
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
+#define SIMDJSON_IS_ARM64 1
+#elif defined(__riscv) && __riscv_xlen == 64
+#define SIMDJSON_IS_RISCV64 1
+
+ #if __riscv_v_intrinsic >= 11000
+ #define SIMDJSON_HAS_RVV_INTRINSICS 1
+ #endif
+
+ #if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
+ #define SIMDJSON_IS_RVV 1 // RISC-V V extension
+ #endif
+
+ // current toolchains don't support fixed-size SIMD types that don't match VLEN directly
+ #if __riscv_v_fixed_vlen >= 128 && __riscv_v_fixed_vlen <= 512
+ #define SIMDJSON_IS_RVV_VLS 1
+ #endif
+
+#elif defined(__loongarch_lp64)
+#define SIMDJSON_IS_LOONGARCH64 1
+#if defined(__loongarch_sx) && defined(__loongarch_asx)
+ #define SIMDJSON_IS_LSX 1
+ #define SIMDJSON_IS_LASX 1 // We can always run both
+#elif defined(__loongarch_sx)
+ #define SIMDJSON_IS_LSX 1
+#endif
+#elif defined(__PPC64__) || defined(_M_PPC64)
+#define SIMDJSON_IS_PPC64 1
+#if defined(__ALTIVEC__)
+#define SIMDJSON_IS_PPC64_VMX 1
+#endif // defined(__ALTIVEC__)
+#else
+#define SIMDJSON_IS_32BITS 1
+
+#if defined(_M_IX86) || defined(__i386__)
+#define SIMDJSON_IS_X86_32BITS 1
+#elif defined(__arm__) || defined(_M_ARM)
+#define SIMDJSON_IS_ARM_32BITS 1
+#elif defined(__PPC__) || defined(_M_PPC)
+#define SIMDJSON_IS_PPC_32BITS 1
+#endif
+
+#endif // defined(__x86_64__) || defined(_M_AMD64)
+#ifndef SIMDJSON_IS_32BITS
+#define SIMDJSON_IS_32BITS 0
+#endif
+
+#if SIMDJSON_IS_32BITS
+#ifndef SIMDJSON_NO_PORTABILITY_WARNING
+// In the future, we should allow programmers
+// to get warning.
+#endif // SIMDJSON_NO_PORTABILITY_WARNING
+#endif // SIMDJSON_IS_32BITS
+
+#define SIMDJSON_CAT_IMPLEMENTATION_(a,...) a ## __VA_ARGS__
+#define SIMDJSON_CAT(a,...) SIMDJSON_CAT_IMPLEMENTATION_(a, __VA_ARGS__)
+
+#define SIMDJSON_STRINGIFY_IMPLEMENTATION_(a,...) #a SIMDJSON_STRINGIFY(__VA_ARGS__)
+#define SIMDJSON_STRINGIFY(a,...) SIMDJSON_CAT_IMPLEMENTATION_(a, __VA_ARGS__)
+
+// this is almost standard?
+#undef SIMDJSON_STRINGIFY_IMPLEMENTATION_
+#undef SIMDJSON_STRINGIFY
+#define SIMDJSON_STRINGIFY_IMPLEMENTATION_(a) #a
+#define SIMDJSON_STRINGIFY(a) SIMDJSON_STRINGIFY_IMPLEMENTATION_(a)
+
+// Our fast kernels require 64-bit systems.
+//
+// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions.
+// Furthermore, the number of SIMD registers is reduced.
+//
+// On 32-bit ARM, we would have smaller registers.
+//
+// The simdjson users should still have the fallback kernel. It is
+// slower, but it should run everywhere.
+
+//
+// Enable valid runtime implementations, and select SIMDJSON_BUILTIN_IMPLEMENTATION
+//
+
+// We are going to use runtime dispatch.
+#if defined(SIMDJSON_IS_X86_64) || defined(SIMDJSON_IS_LSX)
+#ifdef __clang__
+// clang does not have GCC push pop
+// warning: clang attribute push can't be used within a namespace in clang up
+// til 8.0 so SIMDJSON_TARGET_REGION and SIMDJSON_UNTARGET_REGION must be *outside* of a
+// namespace.
+#define SIMDJSON_TARGET_REGION(T) \
+ _Pragma(SIMDJSON_STRINGIFY( \
+ clang attribute push(__attribute__((target(T))), apply_to = function)))
+#define SIMDJSON_UNTARGET_REGION _Pragma("clang attribute pop")
+#elif defined(__GNUC__)
+// GCC is easier
+#define SIMDJSON_TARGET_REGION(T) \
+ _Pragma("GCC push_options") _Pragma(SIMDJSON_STRINGIFY(GCC target(T)))
+#define SIMDJSON_UNTARGET_REGION _Pragma("GCC pop_options")
+#endif // clang then gcc
+
+#endif // defined(SIMDJSON_IS_X86_64) || defined(SIMDJSON_IS_LSX)
+
+// Default target region macros don't do anything.
+#ifndef SIMDJSON_TARGET_REGION
+#define SIMDJSON_TARGET_REGION(T)
+#define SIMDJSON_UNTARGET_REGION
+#endif
+
+// Is threading enabled?
+#if defined(_REENTRANT) || defined(_MT)
+#ifndef SIMDJSON_THREADS_ENABLED
+#define SIMDJSON_THREADS_ENABLED
+#endif
+#endif
+
+// workaround for large stack sizes under -O0.
+// https://github.com/simdjson/simdjson/issues/691
+#ifdef __APPLE__
+#ifndef __OPTIMIZE__
+// Apple systems have small stack sizes in secondary threads.
+// Lack of compiler optimization may generate high stack usage.
+// Users may want to disable threads for safety, but only when
+// in debug mode which we detect by the fact that the __OPTIMIZE__
+// macro is not defined.
+#undef SIMDJSON_THREADS_ENABLED
+#endif
+#endif
+
+
+#if defined(__clang__)
+#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
+#elif defined(__GNUC__)
+#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
+#else
+#define SIMDJSON_NO_SANITIZE_UNDEFINED
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+#define simdjson_pure [[gnu::pure]]
+#else
+#define simdjson_pure
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+#define SIMDJSON_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+# endif // if __has_feature(memory_sanitizer)
+#endif // defined(__has_feature)
+#endif
+// make sure it is defined as 'nothing' if it is unapplicable.
+#ifndef SIMDJSON_NO_SANITIZE_MEMORY
+#define SIMDJSON_NO_SANITIZE_MEMORY
+#endif
+
+#if SIMDJSON_VISUAL_STUDIO
+// This is one case where we do not distinguish between
+// regular visual studio and clang under visual studio.
+// clang under Windows has _stricmp (like visual studio) but not strcasecmp (as clang normally has)
+#define simdjson_strcasecmp _stricmp
+#define simdjson_strncasecmp _strnicmp
+#else
+// The strcasecmp, strncasecmp, and strcasestr functions do not work with multibyte strings (e.g. UTF-8).
+// So they are only useful for ASCII in our context.
+// https://www.gnu.org/software/libunistring/manual/libunistring.html#char-_002a-strings
+#define simdjson_strcasecmp strcasecmp
+#define simdjson_strncasecmp strncasecmp
+#endif
+
+#if (defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG))) && !SIMDJSON_DEVELOPMENT_CHECKS
+// If SIMDJSON_DEVELOPMENT_CHECKS is undefined or 0, we consider that we are in release mode.
+// If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode,
+// then do away with asserts and use __assume.
+// We still recommend that our users set NDEBUG in release mode.
+#if SIMDJSON_VISUAL_STUDIO
+#define SIMDJSON_UNREACHABLE() __assume(0)
+#define SIMDJSON_ASSUME(COND) __assume(COND)
+#else
+#define SIMDJSON_UNREACHABLE() __builtin_unreachable();
+#define SIMDJSON_ASSUME(COND) do { if (!(COND)) __builtin_unreachable(); } while (0)
+#endif
+
+#else // defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG)) && !SIMDJSON_DEVELOPMENT_CHECKS
+// This should only ever be enabled in debug mode.
+#define SIMDJSON_UNREACHABLE() assert(0);
+#define SIMDJSON_ASSUME(COND) assert(COND)
+
+#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
+#elif defined(sun) || defined(__sun)
+#include
+#elif defined(__MVS__)
+#include
+#else
+#ifdef __has_include
+#if __has_include()
+#include
+#endif //__has_include()
+#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 */
+
+namespace simdjson {
+namespace internal {
+/**
+ * @private
+ * Our own implementation of the C++17 to_chars function.
+ * Defined in src/to_chars
+ */
+char *to_chars(char *first, const char *last, double value);
+/**
+ * @private
+ * A number parsing routine.
+ * Defined in src/from_chars
+ */
+double from_chars(const char *first) noexcept;
+double from_chars(const char *first, const char* end) noexcept;
+}
+
+#ifndef SIMDJSON_EXCEPTIONS
+#if defined(__cpp_exceptions) || defined(_CPPUNWIND)
+#define SIMDJSON_EXCEPTIONS 1
+#else
+#define SIMDJSON_EXCEPTIONS 0
+#endif
+#endif
+
+} // namespace simdjson
+
+#if defined(__GNUC__)
+ // Marks a block with a name so that MCA analysis can see it.
+ #define SIMDJSON_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name);
+ #define SIMDJSON_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name);
+ #define SIMDJSON_DEBUG_BLOCK(name, block) BEGIN_DEBUG_BLOCK(name); block; END_DEBUG_BLOCK(name);
+#else
+ #define SIMDJSON_BEGIN_DEBUG_BLOCK(name)
+ #define SIMDJSON_END_DEBUG_BLOCK(name)
+ #define SIMDJSON_DEBUG_BLOCK(name, block)
+#endif
+
+// Align to N-byte boundary
+#define SIMDJSON_ROUNDUP_N(a, n) (((a) + ((n)-1)) & ~((n)-1))
+#define SIMDJSON_ROUNDDOWN_N(a, n) ((a) & ~((n)-1))
+
+#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
+
+#if SIMDJSON_REGULAR_VISUAL_STUDIO
+ // We could use [[deprecated]] but it requires C++14
+ #define simdjson_deprecated __declspec(deprecated)
+
+ #define simdjson_really_inline __forceinline
+ #define simdjson_never_inline __declspec(noinline)
+
+ #define simdjson_unused
+ #define simdjson_warn_unused
+
+ #ifndef simdjson_likely
+ #define simdjson_likely(x) x
+ #endif
+ #ifndef simdjson_unlikely
+ #define simdjson_unlikely(x) x
+ #endif
+
+ #define SIMDJSON_PUSH_DISABLE_WARNINGS __pragma(warning( push ))
+ #define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS __pragma(warning( push, 0 ))
+ #define SIMDJSON_DISABLE_VS_WARNING(WARNING_NUMBER) __pragma(warning( disable : WARNING_NUMBER ))
+ // Get rid of Intellisense-only warnings (Code Analysis)
+ // Though __has_include is C++17, it is supported in Visual Studio 2017 or better (_MSC_VER>=1910).
+ #ifdef __has_include
+ #if __has_include()
+ #include
+ #define SIMDJSON_DISABLE_UNDESIRED_WARNINGS SIMDJSON_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS)
+ #endif
+ #endif
+
+ #ifndef SIMDJSON_DISABLE_UNDESIRED_WARNINGS
+ #define SIMDJSON_DISABLE_UNDESIRED_WARNINGS
+ #endif
+
+ #define SIMDJSON_DISABLE_DEPRECATED_WARNING SIMDJSON_DISABLE_VS_WARNING(4996)
+ #define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
+ #define SIMDJSON_POP_DISABLE_WARNINGS __pragma(warning( pop ))
+
+ #define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
+ #define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
+
+#else // SIMDJSON_REGULAR_VISUAL_STUDIO
+ // We could use [[deprecated]] but it requires C++14
+ #define simdjson_deprecated __attribute__((deprecated))
+
+ #define simdjson_really_inline inline __attribute__((always_inline))
+ #define simdjson_never_inline inline __attribute__((noinline))
+
+ #define simdjson_unused __attribute__((unused))
+ #define simdjson_warn_unused __attribute__((warn_unused_result))
+
+ #ifndef simdjson_likely
+ #define simdjson_likely(x) __builtin_expect(!!(x), 1)
+ #endif
+ #ifndef simdjson_unlikely
+ #define simdjson_unlikely(x) __builtin_expect(!!(x), 0)
+ #endif
+
+ #define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
+ // gcc doesn't seem to disable all warnings with all and extra, add warnings here as necessary
+ // We do it separately for clang since it has different warnings.
+ #ifdef __clang__
+ // clang is missing -Wmaybe-uninitialized.
+ #define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
+ SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wconversion) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wextra) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wattributes) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wimplicit-fallthrough) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wreturn-type) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable)
+ #else // __clang__
+ #define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
+ SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wconversion) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wextra) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wattributes) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wimplicit-fallthrough) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wreturn-type) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wformat-security)
+ #endif // __clang__
+
+ #define SIMDJSON_PRAGMA(P) _Pragma(#P)
+ #define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
+ #if SIMDJSON_CLANG_VISUAL_STUDIO
+ #define SIMDJSON_DISABLE_UNDESIRED_WARNINGS SIMDJSON_DISABLE_GCC_WARNING(-Wmicrosoft-include)
+ #else
+ #define SIMDJSON_DISABLE_UNDESIRED_WARNINGS
+ #endif
+ #define SIMDJSON_DISABLE_DEPRECATED_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wdeprecated-declarations)
+ #define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wstrict-overflow)
+ #define SIMDJSON_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
+
+ #define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
+ SIMDJSON_DISABLE_GCC_WARNING(-Wunused)
+ #define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS SIMDJSON_POP_DISABLE_WARNINGS
+
+
+
+#endif // MSC_VER
+
+#if defined(simdjson_inline)
+ // Prefer the user's definition of simdjson_inline; don't define it ourselves.
+#elif defined(__GNUC__) && !defined(__OPTIMIZE__)
+ // If optimizations are disabled, forcing inlining can lead to significant
+ // code bloat and high compile times. Don't use simdjson_really_inline for
+ // unoptimized builds.
+ #define simdjson_inline inline
+#else
+ // Force inlining for most simdjson functions.
+ #define simdjson_inline simdjson_really_inline
+#endif
+
+#if SIMDJSON_VISUAL_STUDIO
+ /**
+ * Windows users need to do some extra work when building
+ * or using a dynamic library (DLL). When building, we need
+ * to set SIMDJSON_DLLIMPORTEXPORT to __declspec(dllexport).
+ * When *using* the DLL, the user needs to set
+ * SIMDJSON_DLLIMPORTEXPORT __declspec(dllimport).
+ *
+ * Static libraries not need require such work.
+ *
+ * It does not matter here whether you are using
+ * the regular visual studio or clang under visual
+ * studio, you still need to handle these issues.
+ *
+ * Non-Windows systems do not have this complexity.
+ */
+ #if SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY
+ // We set SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY when we build a DLL under Windows.
+ // It should never happen that both SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY and
+ // SIMDJSON_USING_WINDOWS_DYNAMIC_LIBRARY are set.
+ #define SIMDJSON_DLLIMPORTEXPORT __declspec(dllexport)
+ #elif SIMDJSON_USING_WINDOWS_DYNAMIC_LIBRARY
+ // Windows user who call a dynamic library should set SIMDJSON_USING_WINDOWS_DYNAMIC_LIBRARY to 1.
+ #define SIMDJSON_DLLIMPORTEXPORT __declspec(dllimport)
+ #else
+ // We assume by default static linkage
+ #define SIMDJSON_DLLIMPORTEXPORT
+ #endif
+#else
+ #define SIMDJSON_DLLIMPORTEXPORT
+#endif
+
+// C++17 requires string_view.
+#if SIMDJSON_CPLUSPLUS17
+#define SIMDJSON_HAS_STRING_VIEW
+#include // by the standard, this has to be safe.
+#endif
+
+// This macro (__cpp_lib_string_view) has to be defined
+// for C++17 and better, but if it is otherwise defined,
+// we are going to assume that string_view is available
+// even if we do not have C++17 support.
+#ifdef __cpp_lib_string_view
+#define SIMDJSON_HAS_STRING_VIEW
+#include
+#endif
+
+// Some systems have string_view even if we do not have C++17 support,
+// and even if __cpp_lib_string_view is undefined, it is the case
+// with Apple clang version 11.
+// We must handle it. *This is important.*
+#ifndef _MSC_VER
+#ifndef SIMDJSON_HAS_STRING_VIEW
+#if defined __has_include
+// do not combine the next #if with the previous one (unsafe)
+#if __has_include ()
+// now it is safe to trigger the include
+#include // though the file is there, it does not follow that we got the implementation
+#if defined(_LIBCPP_STRING_VIEW)
+// Ah! So we under libc++ which under its Library Fundamentals Technical Specification, which preceded C++17,
+// included string_view.
+// This means that we have string_view *even though* we may not have C++17.
+#define SIMDJSON_HAS_STRING_VIEW
+#endif // _LIBCPP_STRING_VIEW
+#endif // __has_include ()
+#endif // defined __has_include
+#endif // def SIMDJSON_HAS_STRING_VIEW
+#endif // def _MSC_VER
+// end of complicated but important routine to try to detect string_view.
+
+//
+// Backfill std::string_view using nonstd::string_view on systems where
+// we expect that string_view is missing. Important: if we get this wrong,
+// we will end up with two string_view definitions and potential trouble.
+// That is why we work so hard above to avoid it.
+//
+#ifndef SIMDJSON_HAS_STRING_VIEW
+SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
+/* including simdjson/nonstd/string_view.hpp: #include "simdjson/nonstd/string_view.hpp" */
+/* begin file simdjson/nonstd/string_view.hpp */
+// Copyright 2017-2020 by Martin Moene
+//
+// string-view lite, a C++17-like string_view for C++98 and later.
+// For more information see https://github.com/martinmoene/string-view-lite
+//
+// 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)
+
+
+#ifndef NONSTD_SV_LITE_H_INCLUDED
+#define NONSTD_SV_LITE_H_INCLUDED
+
+#define string_view_lite_MAJOR 1
+#define string_view_lite_MINOR 8
+#define string_view_lite_PATCH 0
+
+#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
+
+#define nssv_STRINGIFY( x ) nssv_STRINGIFY_( x )
+#define nssv_STRINGIFY_( x ) #x
+
+// string-view lite configuration:
+
+#define nssv_STRING_VIEW_DEFAULT 0
+#define nssv_STRING_VIEW_NONSTD 1
+#define nssv_STRING_VIEW_STD 2
+
+// tweak header support:
+
+#ifdef __has_include
+# if __has_include()
+# include
+# endif
+#define nssv_HAVE_TWEAK_HEADER 1
+#else
+#define nssv_HAVE_TWEAK_HEADER 0
+//# pragma message("string_view.hpp: Note: Tweak header not supported.")
+#endif
+
+// string_view selection and configuration:
+
+#if !defined( nssv_CONFIG_SELECT_STRING_VIEW )
+# define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD )
+#endif
+
+#ifndef nssv_CONFIG_STD_SV_OPERATOR
+# define nssv_CONFIG_STD_SV_OPERATOR 0
+#endif
+
+#ifndef nssv_CONFIG_USR_SV_OPERATOR
+# define nssv_CONFIG_USR_SV_OPERATOR 1
+#endif
+
+#ifdef nssv_CONFIG_CONVERSION_STD_STRING
+# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING
+# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING
+#endif
+
+#ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
+# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1
+#endif
+
+#ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1
+#endif
+
+#ifndef nssv_CONFIG_NO_STREAM_INSERTION
+# define nssv_CONFIG_NO_STREAM_INSERTION 0
+#endif
+
+#ifndef nssv_CONFIG_CONSTEXPR11_STD_SEARCH
+# define nssv_CONFIG_CONSTEXPR11_STD_SEARCH 1
+#endif
+
+// Control presence of exception handling (try and auto discover):
+
+#ifndef nssv_CONFIG_NO_EXCEPTIONS
+# if defined(_MSC_VER)
+# include // for _HAS_EXCEPTIONS
+# endif
+# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
+# define nssv_CONFIG_NO_EXCEPTIONS 0
+# else
+# define nssv_CONFIG_NO_EXCEPTIONS 1
+# endif
+#endif
+
+// C++ language version detection (C++23 is speculative):
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
+
+#ifndef nssv_CPLUSPLUS
+# if defined(_MSVC_LANG ) && !defined(__clang__)
+# define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
+# else
+# define nssv_CPLUSPLUS __cplusplus
+# endif
+#endif
+
+#define nssv_CPP98_OR_GREATER ( nssv_CPLUSPLUS >= 199711L )
+#define nssv_CPP11_OR_GREATER ( nssv_CPLUSPLUS >= 201103L )
+#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L )
+#define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L )
+#define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L )
+#define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202002L )
+#define nssv_CPP23_OR_GREATER ( nssv_CPLUSPLUS >= 202300L )
+
+// use C++17 std::string_view if available and requested:
+
+#if nssv_CPP17_OR_GREATER && defined(__has_include )
+# if __has_include( )
+# define nssv_HAVE_STD_STRING_VIEW 1
+# else
+# define nssv_HAVE_STD_STRING_VIEW 0
+# endif
+#else
+# define nssv_HAVE_STD_STRING_VIEW 0
+#endif
+
+#define nssv_USES_STD_STRING_VIEW ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) )
+
+#define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW )
+#define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH
+
+//
+// Use C++17 std::string_view:
+//
+
+#if nssv_USES_STD_STRING_VIEW
+
+#include
+
+// Extensions for std::string:
+
+#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+
+#include
+
+namespace nonstd {
+
+template< class CharT, class Traits, class Allocator = std::allocator >
+std::basic_string
+to_string( std::basic_string_view v, Allocator const & a = Allocator() )
+{
+ return std::basic_string( v.begin(), v.end(), a );
+}
+
+template< class CharT, class Traits, class Allocator >
+std::basic_string_view
+to_string_view( std::basic_string const & s )
+{
+ return std::basic_string_view( s.data(), s.size() );
+}
+
+// Literal operators sv and _sv:
+
+#if nssv_CONFIG_STD_SV_OPERATOR
+
+using namespace std::literals::string_view_literals;
+
+#endif
+
+#if nssv_CONFIG_USR_SV_OPERATOR
+
+inline namespace literals {
+inline namespace string_view_literals {
+
+
+constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1)
+{
+ return std::string_view{ str, len };
+}
+
+constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2)
+{
+ return std::u16string_view{ str, len };
+}
+
+constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3)
+{
+ return std::u32string_view{ str, len };
+}
+
+constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4)
+{
+ return std::wstring_view{ str, len };
+}
+
+}} // namespace literals::string_view_literals
+
+#endif // nssv_CONFIG_USR_SV_OPERATOR
+
+} // namespace nonstd
+
+#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+
+namespace nonstd {
+
+using std::string_view;
+using std::wstring_view;
+using std::u16string_view;
+using std::u32string_view;
+using std::basic_string_view;
+
+// literal "sv" and "_sv", see above
+
+using std::operator==;
+using std::operator!=;
+using std::operator<;
+using std::operator<=;
+using std::operator>;
+using std::operator>=;
+
+using std::operator<<;
+
+} // namespace nonstd
+
+#else // nssv_HAVE_STD_STRING_VIEW
+
+//
+// Before C++17: use string_view lite:
+//
+
+// Compiler versions:
+//
+// MSVC++ 6.0 _MSC_VER == 1200 nssv_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
+// MSVC++ 7.0 _MSC_VER == 1300 nssv_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
+// MSVC++ 7.1 _MSC_VER == 1310 nssv_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
+// MSVC++ 8.0 _MSC_VER == 1400 nssv_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
+// MSVC++ 9.0 _MSC_VER == 1500 nssv_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
+// MSVC++ 10.0 _MSC_VER == 1600 nssv_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
+// MSVC++ 11.0 _MSC_VER == 1700 nssv_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
+// MSVC++ 12.0 _MSC_VER == 1800 nssv_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
+// MSVC++ 14.0 _MSC_VER == 1900 nssv_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
+// MSVC++ 14.1 _MSC_VER >= 1910 nssv_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
+// MSVC++ 14.2 _MSC_VER >= 1920 nssv_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
+
+#if defined(_MSC_VER ) && !defined(__clang__)
+# define nssv_COMPILER_MSVC_VER (_MSC_VER )
+# define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
+#else
+# define nssv_COMPILER_MSVC_VER 0
+# define nssv_COMPILER_MSVC_VERSION 0
+#endif
+
+#define nssv_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
+
+#if defined( __apple_build_version__ )
+# define nssv_COMPILER_APPLECLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
+# define nssv_COMPILER_CLANG_VERSION 0
+#elif defined( __clang__ )
+# define nssv_COMPILER_APPLECLANG_VERSION 0
+# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
+#else
+# define nssv_COMPILER_APPLECLANG_VERSION 0
+# define nssv_COMPILER_CLANG_VERSION 0
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+# define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#else
+# define nssv_COMPILER_GNUC_VERSION 0
+#endif
+
+// half-open range [lo..hi):
+#define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
+
+// Presence of language and library features:
+
+#ifdef _HAS_CPP0X
+# define nssv_HAS_CPP0X _HAS_CPP0X
+#else
+# define nssv_HAS_CPP0X 0
+#endif
+
+// Unless defined otherwise below, consider VC14 as C++11 for string-view-lite:
+
+#if nssv_COMPILER_MSVC_VER >= 1900
+# undef nssv_CPP11_OR_GREATER
+# define nssv_CPP11_OR_GREATER 1
+#endif
+
+#define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500)
+#define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600)
+#define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700)
+#define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800)
+#define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900)
+#define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910)
+
+#define nssv_CPP14_000 (nssv_CPP14_OR_GREATER)
+#define nssv_CPP17_000 (nssv_CPP17_OR_GREATER)
+
+// Presence of C++11 language features:
+
+#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140
+#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140
+#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140
+#define nssv_HAVE_IS_DEFAULT nssv_CPP11_140
+#define nssv_HAVE_IS_DELETE nssv_CPP11_140
+#define nssv_HAVE_NOEXCEPT nssv_CPP11_140
+#define nssv_HAVE_NULLPTR nssv_CPP11_100
+#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140
+#define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140
+#define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140
+#define nssv_HAVE_WCHAR16_T nssv_CPP11_100
+#define nssv_HAVE_WCHAR32_T nssv_CPP11_100
+
+#if ! ( ( nssv_CPP11_OR_GREATER && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) )
+# define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140
+#else
+# define nssv_HAVE_STD_DEFINED_LITERALS 0
+#endif
+
+// Presence of C++14 language features:
+
+#define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000
+
+// Presence of C++17 language features:
+
+#define nssv_HAVE_NODISCARD nssv_CPP17_000
+
+// Presence of C++ library features:
+
+#define nssv_HAVE_STD_HASH nssv_CPP11_120
+
+// Presence of compiler intrinsics:
+
+// Providing char-type specializations for compare() and length() that
+// use compiler intrinsics can improve compile- and run-time performance.
+//
+// The challenge is in using the right combinations of builtin availability
+// and its constexpr-ness.
+//
+// | compiler | __builtin_memcmp (constexpr) | memcmp (constexpr) |
+// |----------|------------------------------|---------------------|
+// | clang | 4.0 (>= 4.0 ) | any (? ) |
+// | clang-a | 9.0 (>= 9.0 ) | any (? ) |
+// | gcc | any (constexpr) | any (? ) |
+// | msvc | >= 14.2 C++17 (>= 14.2 ) | any (? ) |
+
+#define nssv_HAVE_BUILTIN_VER ( (nssv_CPP17_000 && nssv_COMPILER_MSVC_VERSION >= 142) || nssv_COMPILER_GNUC_VERSION > 0 || nssv_COMPILER_CLANG_VERSION >= 400 || nssv_COMPILER_APPLECLANG_VERSION >= 900 )
+#define nssv_HAVE_BUILTIN_CE ( nssv_HAVE_BUILTIN_VER )
+
+#define nssv_HAVE_BUILTIN_MEMCMP ( (nssv_HAVE_CONSTEXPR_14 && nssv_HAVE_BUILTIN_CE) || !nssv_HAVE_CONSTEXPR_14 )
+#define nssv_HAVE_BUILTIN_STRLEN ( (nssv_HAVE_CONSTEXPR_11 && nssv_HAVE_BUILTIN_CE) || !nssv_HAVE_CONSTEXPR_11 )
+
+#ifdef __has_builtin
+# define nssv_HAVE_BUILTIN( x ) __has_builtin( x )
+#else
+# define nssv_HAVE_BUILTIN( x ) 0
+#endif
+
+#if nssv_HAVE_BUILTIN(__builtin_memcmp) || nssv_HAVE_BUILTIN_VER
+# define nssv_BUILTIN_MEMCMP __builtin_memcmp
+#else
+# define nssv_BUILTIN_MEMCMP memcmp
+#endif
+
+#if nssv_HAVE_BUILTIN(__builtin_strlen) || nssv_HAVE_BUILTIN_VER
+# define nssv_BUILTIN_STRLEN __builtin_strlen
+#else
+# define nssv_BUILTIN_STRLEN strlen
+#endif
+
+// C++ feature usage:
+
+#if nssv_HAVE_CONSTEXPR_11
+# define nssv_constexpr constexpr
+#else
+# define nssv_constexpr /*constexpr*/
+#endif
+
+#if nssv_HAVE_CONSTEXPR_14
+# define nssv_constexpr14 constexpr
+#else
+# define nssv_constexpr14 /*constexpr*/
+#endif
+
+#if nssv_HAVE_EXPLICIT_CONVERSION
+# define nssv_explicit explicit
+#else
+# define nssv_explicit /*explicit*/
+#endif
+
+#if nssv_HAVE_INLINE_NAMESPACE
+# define nssv_inline_ns inline
+#else
+# define nssv_inline_ns /*inline*/
+#endif
+
+#if nssv_HAVE_NOEXCEPT
+# define nssv_noexcept noexcept
+#else
+# define nssv_noexcept /*noexcept*/
+#endif
+
+//#if nssv_HAVE_REF_QUALIFIER
+//# define nssv_ref_qual &
+//# define nssv_refref_qual &&
+//#else
+//# define nssv_ref_qual /*&*/
+//# define nssv_refref_qual /*&&*/
+//#endif
+
+#if nssv_HAVE_NULLPTR
+# define nssv_nullptr nullptr
+#else
+# define nssv_nullptr NULL
+#endif
+
+#if nssv_HAVE_NODISCARD
+# define nssv_nodiscard simdjson_warn_unused
+#else
+# define nssv_nodiscard /*simdjson_warn_unused*/
+#endif
+
+// Additional includes:
+
+#include
+#include
+#include
+#include
+#include // std::char_traits<>
+
+#if ! nssv_CONFIG_NO_STREAM_INSERTION
+# include
+#endif
+
+#if ! nssv_CONFIG_NO_EXCEPTIONS
+# include
+#endif
+
+#if nssv_CPP11_OR_GREATER
+# include
+#endif
+
+// Clang, GNUC, MSVC warning suppression macros:
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wreserved-user-defined-literal"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wuser-defined-literals"
+#elif nssv_COMPILER_GNUC_VERSION >= 480
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wliteral-suffix"
+#endif // __clang__
+
+#if nssv_COMPILER_MSVC_VERSION >= 140
+# define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]]
+# define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) )
+# define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes))
+#else
+# define nssv_SUPPRESS_MSGSL_WARNING(expr)
+# define nssv_SUPPRESS_MSVC_WARNING(code, descr)
+# define nssv_DISABLE_MSVC_WARNINGS(codes)
+#endif
+
+#if defined(__clang__)
+# define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
+#elif nssv_COMPILER_GNUC_VERSION >= 480
+# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
+#elif nssv_COMPILER_MSVC_VERSION >= 140
+# define nssv_RESTORE_WARNINGS() __pragma(warning(pop ))
+#else
+# define nssv_RESTORE_WARNINGS()
+#endif
+
+// Suppress the following MSVC (GSL) warnings:
+// - C4455, non-gsl : 'operator ""sv': literal suffix identifiers that do not
+// start with an underscore are reserved
+// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;
+// use brace initialization, gsl::narrow_cast or gsl::narow
+// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
+
+nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )
+//nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" )
+//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix )
+
+namespace nonstd { namespace sv_lite {
+
+//
+// basic_string_view declaration:
+//
+
+template
+<
+ class CharT,
+ class Traits = std::char_traits
+>
+class basic_string_view;
+
+namespace detail {
+
+// support constexpr comparison in C++14;
+// for C++17 and later, use provided traits:
+
+template< typename CharT >
+inline nssv_constexpr14 int compare( CharT const * s1, CharT const * s2, std::size_t count )
+{
+ while ( count-- != 0 )
+ {
+ if ( *s1 < *s2 ) return -1;
+ if ( *s1 > *s2 ) return +1;
+ ++s1; ++s2;
+ }
+ return 0;
+}
+
+#if nssv_HAVE_BUILTIN_MEMCMP
+
+// specialization of compare() for char, see also generic compare() above:
+
+inline nssv_constexpr14 int compare( char const * s1, char const * s2, std::size_t count )
+{
+ return nssv_BUILTIN_MEMCMP( s1, s2, count );
+}
+
+#endif
+
+#if nssv_HAVE_BUILTIN_STRLEN
+
+// specialization of length() for char, see also generic length() further below:
+
+inline nssv_constexpr std::size_t length( char const * s )
+{
+ return nssv_BUILTIN_STRLEN( s );
+}
+
+#endif
+
+#if defined(__OPTIMIZE__)
+
+// gcc, clang provide __OPTIMIZE__
+// Expect tail call optimization to make length() non-recursive:
+
+template< typename CharT >
+inline nssv_constexpr std::size_t length( CharT * s, std::size_t result = 0 )
+{
+ return *s == '\0' ? result : length( s + 1, result + 1 );
+}
+
+#else // OPTIMIZE
+
+// non-recursive:
+
+template< typename CharT >
+inline nssv_constexpr14 std::size_t length( CharT * s )
+{
+ std::size_t result = 0;
+ while ( *s++ != '\0' )
+ {
+ ++result;
+ }
+ return result;
+}
+
+#endif // OPTIMIZE
+
+#if nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
+#if defined(__OPTIMIZE__)
+
+// gcc, clang provide __OPTIMIZE__
+// Expect tail call optimization to make search() non-recursive:
+
+template< class CharT, class Traits = std::char_traits >
+constexpr const CharT* search( basic_string_view haystack, basic_string_view needle )
+{
+ return haystack.starts_with( needle ) ? haystack.begin() :
+ haystack.empty() ? haystack.end() : search( haystack.substr(1), needle );
+}
+
+#else // OPTIMIZE
+
+// non-recursive:
+
+#if nssv_CONFIG_CONSTEXPR11_STD_SEARCH
+
+template< class CharT, class Traits = std::char_traits >
+constexpr const CharT* search( basic_string_view haystack, basic_string_view needle )
+{
+ return std::search( haystack.begin(), haystack.end(), needle.begin(), needle.end() );
+}
+
+#else // nssv_CONFIG_CONSTEXPR11_STD_SEARCH
+
+template< class CharT, class Traits = std::char_traits >
+nssv_constexpr14 const CharT* search( basic_string_view haystack, basic_string_view needle )
+{
+ while ( needle.size() <= haystack.size() )
+ {
+ if ( haystack.starts_with(needle) )
+ {
+ return haystack.cbegin();
+ }
+ haystack = basic_string_view{ haystack.begin() + 1, haystack.size() - 1U };
+ }
+ return haystack.cend();
+}
+#endif // nssv_CONFIG_CONSTEXPR11_STD_SEARCH
+
+#endif // OPTIMIZE
+#endif // nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
+
+} // namespace detail
+
+//
+// basic_string_view:
+//
+
+template
+<
+ class CharT,
+ class Traits /* = std::char_traits */
+>
+class basic_string_view
+{
+public:
+ // Member types:
+
+ typedef Traits traits_type;
+ typedef CharT value_type;
+
+ typedef CharT * pointer;
+ typedef CharT const * const_pointer;
+ typedef CharT & reference;
+ typedef CharT const & const_reference;
+
+ typedef const_pointer iterator;
+ typedef const_pointer const_iterator;
+ typedef std::reverse_iterator< const_iterator > reverse_iterator;
+ typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
+
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ // 24.4.2.1 Construction and assignment:
+
+ nssv_constexpr basic_string_view() nssv_noexcept
+ : data_( nssv_nullptr )
+ , size_( 0 )
+ {}
+
+#if nssv_CPP11_OR_GREATER
+ nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default;
+#else
+ nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept
+ : data_( other.data_)
+ , size_( other.size_)
+ {}
+#endif
+
+ nssv_constexpr basic_string_view( CharT const * s, size_type count ) nssv_noexcept // non-standard noexcept
+ : data_( s )
+ , size_( count )
+ {}
+
+ nssv_constexpr basic_string_view( CharT const * s) nssv_noexcept // non-standard noexcept
+ : data_( s )
+#if nssv_CPP17_OR_GREATER
+ , size_( Traits::length(s) )
+#elif nssv_CPP11_OR_GREATER
+ , size_( detail::length(s) )
+#else
+ , size_( Traits::length(s) )
+#endif
+ {}
+
+#if nssv_HAVE_NULLPTR
+# if nssv_HAVE_IS_DELETE
+ nssv_constexpr basic_string_view( std::nullptr_t ) nssv_noexcept = delete;
+# else
+ private: nssv_constexpr basic_string_view( std::nullptr_t ) nssv_noexcept; public:
+# endif
+#endif
+
+ // Assignment:
+
+#if nssv_CPP11_OR_GREATER
+ nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default;
+#else
+ nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept
+ {
+ data_ = other.data_;
+ size_ = other.size_;
+ return *this;
+ }
+#endif
+
+ // 24.4.2.2 Iterator support:
+
+ nssv_constexpr const_iterator begin() const nssv_noexcept { return data_; }
+ nssv_constexpr const_iterator end() const nssv_noexcept { return data_ + size_; }
+
+ nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); }
+ nssv_constexpr const_iterator cend() const nssv_noexcept { return end(); }
+
+ nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept { return const_reverse_iterator( end() ); }
+ nssv_constexpr const_reverse_iterator rend() const nssv_noexcept { return const_reverse_iterator( begin() ); }
+
+ nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); }
+ nssv_constexpr const_reverse_iterator crend() const nssv_noexcept { return rend(); }
+
+ // 24.4.2.3 Capacity:
+
+ nssv_constexpr size_type size() const nssv_noexcept { return size_; }
+ nssv_constexpr size_type length() const nssv_noexcept { return size_; }
+ nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); }
+
+ // since C++20
+ nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept
+ {
+ return 0 == size_;
+ }
+
+ // 24.4.2.4 Element access:
+
+ nssv_constexpr const_reference operator[]( size_type pos ) const
+ {
+ return data_at( pos );
+ }
+
+ nssv_constexpr14 const_reference at( size_type pos ) const
+ {
+#if nssv_CONFIG_NO_EXCEPTIONS
+ assert( pos < size() );
+#else
+ if ( pos >= size() )
+ {
+ throw std::out_of_range("nonstd::string_view::at()");
+ }
+#endif
+ return data_at( pos );
+ }
+
+ nssv_constexpr const_reference front() const { return data_at( 0 ); }
+ nssv_constexpr const_reference back() const { return data_at( size() - 1 ); }
+
+ nssv_constexpr const_pointer data() const nssv_noexcept { return data_; }
+
+ // 24.4.2.5 Modifiers:
+
+ nssv_constexpr14 void remove_prefix( size_type n )
+ {
+ assert( n <= size() );
+ data_ += n;
+ size_ -= n;
+ }
+
+ nssv_constexpr14 void remove_suffix( size_type n )
+ {
+ assert( n <= size() );
+ size_ -= n;
+ }
+
+ nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept
+ {
+ const basic_string_view tmp(other);
+ other = *this;
+ *this = tmp;
+ }
+
+ // 24.4.2.6 String operations:
+
+ size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const
+ {
+#if nssv_CONFIG_NO_EXCEPTIONS
+ assert( pos <= size() );
+#else
+ if ( pos > size() )
+ {
+ throw std::out_of_range("nonstd::string_view::copy()");
+ }
+#endif
+ const size_type rlen = (std::min)( n, size() - pos );
+
+ (void) Traits::copy( dest, data() + pos, rlen );
+
+ return rlen;
+ }
+
+ nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const
+ {
+#if nssv_CONFIG_NO_EXCEPTIONS
+ assert( pos <= size() );
+#else
+ if ( pos > size() )
+ {
+ throw std::out_of_range("nonstd::string_view::substr()");
+ }
+#endif
+ return basic_string_view( data() + pos, (std::min)( n, size() - pos ) );
+ }
+
+ // compare(), 6x:
+
+ nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1)
+ {
+#if nssv_CPP17_OR_GREATER
+ if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )
+#else
+ if ( const int result = detail::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )
+#endif
+ {
+ return result;
+ }
+
+ return size() == other.size() ? 0 : size() < other.size() ? -1 : 1;
+ }
+
+ nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2)
+ {
+ return substr( pos1, n1 ).compare( other );
+ }
+
+ nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3)
+ {
+ return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) );
+ }
+
+ nssv_constexpr int compare( CharT const * s ) const // (4)
+ {
+ return compare( basic_string_view( s ) );
+ }
+
+ nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5)
+ {
+ return substr( pos1, n1 ).compare( basic_string_view( s ) );
+ }
+
+ nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6)
+ {
+ return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) );
+ }
+
+ // 24.4.2.7 Searching:
+
+ // starts_with(), 3x, since C++20:
+
+ nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept // (1)
+ {
+ return size() >= v.size() && compare( 0, v.size(), v ) == 0;
+ }
+
+ nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept // (2)
+ {
+ return starts_with( basic_string_view( &c, 1 ) );
+ }
+
+ nssv_constexpr bool starts_with( CharT const * s ) const // (3)
+ {
+ return starts_with( basic_string_view( s ) );
+ }
+
+ // ends_with(), 3x, since C++20:
+
+ nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept // (1)
+ {
+ return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0;
+ }
+
+ nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept // (2)
+ {
+ return ends_with( basic_string_view( &c, 1 ) );
+ }
+
+ nssv_constexpr bool ends_with( CharT const * s ) const // (3)
+ {
+ return ends_with( basic_string_view( s ) );
+ }
+
+ // find(), 4x:
+
+ nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
+ {
+ return assert( v.size() == 0 || v.data() != nssv_nullptr )
+ , pos >= size()
+ ? npos : to_pos(
+#if nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
+ detail::search( substr(pos), v )
+#else
+ std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq )
+#endif
+ );
+ }
+
+ nssv_constexpr size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2)
+ {
+ return find( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr size_type find( CharT const * s, size_type pos, size_type n ) const // (3)
+ {
+ return find( basic_string_view( s, n ), pos );
+ }
+
+ nssv_constexpr size_type find( CharT const * s, size_type pos = 0 ) const // (4)
+ {
+ return find( basic_string_view( s ), pos );
+ }
+
+ // rfind(), 4x:
+
+ nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1)
+ {
+ if ( size() < v.size() )
+ {
+ return npos;
+ }
+
+ if ( v.empty() )
+ {
+ return (std::min)( size(), pos );
+ }
+
+ const_iterator last = cbegin() + (std::min)( size() - v.size(), pos ) + v.size();
+ const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq );
+
+ return result != last ? size_type( result - cbegin() ) : npos;
+ }
+
+ nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept // (2)
+ {
+ return rfind( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const // (3)
+ {
+ return rfind( basic_string_view( s, n ), pos );
+ }
+
+ nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const // (4)
+ {
+ return rfind( basic_string_view( s ), pos );
+ }
+
+ // find_first_of(), 4x:
+
+ nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
+ {
+ return pos >= size()
+ ? npos
+ : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );
+ }
+
+ nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2)
+ {
+ return find_first_of( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const // (3)
+ {
+ return find_first_of( basic_string_view( s, n ), pos );
+ }
+
+ nssv_constexpr size_type find_first_of( CharT const * s, size_type pos = 0 ) const // (4)
+ {
+ return find_first_of( basic_string_view( s ), pos );
+ }
+
+ // find_last_of(), 4x:
+
+ nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1)
+ {
+ return empty()
+ ? npos
+ : pos >= size()
+ ? find_last_of( v, size() - 1 )
+ : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) );
+ }
+
+ nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2)
+ {
+ return find_last_of( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const // (3)
+ {
+ return find_last_of( basic_string_view( s, count ), pos );
+ }
+
+ nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const // (4)
+ {
+ return find_last_of( basic_string_view( s ), pos );
+ }
+
+ // find_first_not_of(), 4x:
+
+ nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
+ {
+ return pos >= size()
+ ? npos
+ : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) );
+ }
+
+ nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2)
+ {
+ return find_first_not_of( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const // (3)
+ {
+ return find_first_not_of( basic_string_view( s, count ), pos );
+ }
+
+ nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const // (4)
+ {
+ return find_first_not_of( basic_string_view( s ), pos );
+ }
+
+ // find_last_not_of(), 4x:
+
+ nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1)
+ {
+ return empty()
+ ? npos
+ : pos >= size()
+ ? find_last_not_of( v, size() - 1 )
+ : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) );
+ }
+
+ nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2)
+ {
+ return find_last_not_of( basic_string_view( &c, 1 ), pos );
+ }
+
+ nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const // (3)
+ {
+ return find_last_not_of( basic_string_view( s, count ), pos );
+ }
+
+ nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const // (4)
+ {
+ return find_last_not_of( basic_string_view( s ), pos );
+ }
+
+ // Constants:
+
+#if nssv_CPP17_OR_GREATER
+ static nssv_constexpr size_type npos = size_type(-1);
+#elif nssv_CPP11_OR_GREATER
+ enum : size_type { npos = size_type(-1) };
+#else
+ enum { npos = size_type(-1) };
+#endif
+
+private:
+ struct not_in_view
+ {
+ const basic_string_view v;
+
+ nssv_constexpr explicit not_in_view( basic_string_view v_ ) : v( v_ ) {}
+
+ nssv_constexpr bool operator()( CharT c ) const
+ {
+ return npos == v.find_first_of( c );
+ }
+ };
+
+ nssv_constexpr size_type to_pos( const_iterator it ) const
+ {
+ return it == cend() ? npos : size_type( it - cbegin() );
+ }
+
+ nssv_constexpr size_type to_pos( const_reverse_iterator it ) const
+ {
+ return it == crend() ? npos : size_type( crend() - it - 1 );
+ }
+
+ nssv_constexpr const_reference data_at( size_type pos ) const
+ {
+#if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 )
+ return data_[pos];
+#else
+ return assert( pos < size() ), data_[pos];
+#endif
+ }
+
+private:
+ const_pointer data_;
+ size_type size_;
+
+public:
+#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
+
+ template< class Allocator >
+ basic_string_view( std::basic_string const & s ) nssv_noexcept
+ : data_( s.data() )
+ , size_( s.size() )
+ {}
+
+#if nssv_HAVE_EXPLICIT_CONVERSION
+
+ template< class Allocator >
+ explicit operator std::basic_string() const
+ {
+ return to_string( Allocator() );
+ }
+
+#endif // nssv_HAVE_EXPLICIT_CONVERSION
+
+#if nssv_CPP11_OR_GREATER
+
+ template< class Allocator = std::allocator >
+ std::basic_string
+ to_string( Allocator const & a = Allocator() ) const
+ {
+ return std::basic_string( begin(), end(), a );
+ }
+
+#else
+
+ std::basic_string
+ to_string() const
+ {
+ return std::basic_string( begin(), end() );
+ }
+
+ template< class Allocator >
+ std::basic_string
+ to_string( Allocator const & a ) const
+ {
+ return std::basic_string( begin(), end(), a );
+ }
+
+#endif // nssv_CPP11_OR_GREATER
+
+#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
+};
+
+//
+// Non-member functions:
+//
+
+// 24.4.3 Non-member comparison functions:
+// lexicographically compare two string views (function template):
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator== (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator!= (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator< (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) < 0; }
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator<= (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) <= 0; }
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator> (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) > 0; }
+
+template< class CharT, class Traits >
+nssv_constexpr bool operator>= (
+ basic_string_view lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) >= 0; }
+
+// Let S be basic_string_view, and sv be an instance of S.
+// Implementations shall provide sufficient additional overloads marked
+// constexpr and noexcept so that an object t with an implicit conversion
+// to S can be compared according to Table 67.
+
+#if ! nssv_CPP11_OR_GREATER || nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 )
+
+// accommodate for older compilers:
+
+// ==
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator==(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return lhs.size() == detail::length( rhs ) && lhs.compare( rhs ) == 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator==(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return detail::length( lhs ) == rhs.size() && rhs.compare( lhs ) == 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator==(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator==(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
+
+// !=
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator!=(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator!=(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator!=(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator!=(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+// <
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) < 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return rhs.compare( lhs ) > 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) < 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return rhs.compare( lhs ) > 0; }
+
+// <=
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<=(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) <= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<=(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return rhs.compare( lhs ) >= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<=(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) <= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator<=(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return rhs.compare( lhs ) >= 0; }
+
+// >
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) > 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return rhs.compare( lhs ) < 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) > 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return rhs.compare( lhs ) < 0; }
+
+// >=
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>=(
+ basic_string_view lhs,
+ CharT const * rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) >= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>=(
+ CharT const * lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return rhs.compare( lhs ) <= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>=(
+ basic_string_view lhs,
+ std::basic_string rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) >= 0; }
+
+template< class CharT, class Traits>
+nssv_constexpr bool operator>=(
+ std::basic_string rhs,
+ basic_string_view lhs ) nssv_noexcept
+{ return rhs.compare( lhs ) <= 0; }
+
+#else // newer compilers:
+
+#define nssv_BASIC_STRING_VIEW_I(T,U) typename std::decay< basic_string_view >::type
+
+#if defined(_MSC_VER) // issue 40
+# define nssv_MSVC_ORDER(x) , int=x
+#else
+# define nssv_MSVC_ORDER(x) /*, int=x*/
+#endif
+
+// ==
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator==(
+ basic_string_view lhs,
+ nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept
+{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator==(
+ nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,
+ basic_string_view rhs ) nssv_noexcept
+{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }
+
+// !=
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator!= (
+ basic_string_view < CharT, Traits > lhs,
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator!= (
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
+ basic_string_view < CharT, Traits > rhs ) nssv_noexcept
+{ return !( lhs == rhs ); }
+
+// <
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator< (
+ basic_string_view < CharT, Traits > lhs,
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) < 0; }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator< (
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
+ basic_string_view < CharT, Traits > rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) < 0; }
+
+// <=
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator<= (
+ basic_string_view < CharT, Traits > lhs,
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) <= 0; }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator<= (
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
+ basic_string_view < CharT, Traits > rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) <= 0; }
+
+// >
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator> (
+ basic_string_view < CharT, Traits > lhs,
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) > 0; }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator> (
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
+ basic_string_view < CharT, Traits > rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) > 0; }
+
+// >=
+
+template< class CharT, class Traits nssv_MSVC_ORDER(1) >
+nssv_constexpr bool operator>= (
+ basic_string_view < CharT, Traits > lhs,
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) >= 0; }
+
+template< class CharT, class Traits nssv_MSVC_ORDER(2) >
+nssv_constexpr bool operator>= (
+ nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,
+ basic_string_view < CharT, Traits > rhs ) nssv_noexcept
+{ return lhs.compare( rhs ) >= 0; }
+
+#undef nssv_MSVC_ORDER
+#undef nssv_BASIC_STRING_VIEW_I
+
+#endif // compiler-dependent approach to comparisons
+
+// 24.4.4 Inserters and extractors:
+
+#if ! nssv_CONFIG_NO_STREAM_INSERTION
+
+namespace detail {
+
+template< class Stream >
+void write_padding( Stream & os, std::streamsize n )
+{
+ for ( std::streamsize i = 0; i < n; ++i )
+ os.rdbuf()->sputc( os.fill() );
+}
+
+template< class Stream, class View >
+Stream & write_to_stream( Stream & os, View const & sv )
+{
+ typename Stream::sentry sentry( os );
+
+ if ( !sentry )
+ return os;
+
+ const std::streamsize length = static_cast( sv.length() );
+
+ // Whether, and how, to pad:
+ const bool pad = ( length < os.width() );
+ const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right;
+
+ if ( left_pad )
+ write_padding( os, os.width() - length );
+
+ // Write span characters:
+ os.rdbuf()->sputn( sv.begin(), length );
+
+ if ( pad && !left_pad )
+ write_padding( os, os.width() - length );
+
+ // Reset output stream width:
+ os.width( 0 );
+
+ return os;
+}
+
+} // namespace detail
+
+template< class CharT, class Traits >
+std::basic_ostream &
+operator<<(
+ std::basic_ostream& os,
+ basic_string_view sv )
+{
+ return detail::write_to_stream( os, sv );
+}
+
+#endif // nssv_CONFIG_NO_STREAM_INSERTION
+
+// Several typedefs for common character types are provided:
+
+typedef basic_string_view string_view;
+typedef basic_string_view wstring_view;
+#if nssv_HAVE_WCHAR16_T
+typedef basic_string_view u16string_view;
+typedef basic_string_view u32string_view;
+#endif
+
+}} // namespace nonstd::sv_lite
+
+//
+// 24.4.6 Suffix for basic_string_view literals:
+//
+
+#if nssv_HAVE_USER_DEFINED_LITERALS
+
+namespace nonstd {
+nssv_inline_ns namespace literals {
+nssv_inline_ns namespace string_view_literals {
+
+#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
+
+nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1)
+{
+ return nonstd::sv_lite::string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
+{
+ return nonstd::sv_lite::u16string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
+{
+ return nonstd::sv_lite::u32string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
+{
+ return nonstd::sv_lite::wstring_view{ str, len };
+}
+
+#endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
+
+#if nssv_CONFIG_USR_SV_OPERATOR
+
+nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1)
+{
+ return nonstd::sv_lite::string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
+{
+ return nonstd::sv_lite::u16string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
+{
+ return nonstd::sv_lite::u32string_view{ str, len };
+}
+
+nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
+{
+ return nonstd::sv_lite::wstring_view{ str, len };
+}
+
+#endif // nssv_CONFIG_USR_SV_OPERATOR
+
+}}} // namespace nonstd::literals::string_view_literals
+
+#endif
+
+//
+// Extensions for std::string:
+//
+
+#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+
+namespace nonstd {
+namespace sv_lite {
+
+// Exclude MSVC 14 (19.00): it yields ambiguous to_string():
+
+#if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140
+
+template< class CharT, class Traits, class Allocator = std::allocator >
+std::basic_string
+to_string( basic_string_view v, Allocator const & a = Allocator() )
+{
+ return std::basic_string( v.begin(), v.end(), a );
+}
+
+#else
+
+template< class CharT, class Traits >
+std::basic_string
+to_string( basic_string_view v )
+{
+ return std::basic_string( v.begin(), v.end() );
+}
+
+template< class CharT, class Traits, class Allocator >
+std::basic_string
+to_string( basic_string_view v, Allocator const & a )
+{
+ return std::basic_string( v.begin(), v.end(), a );
+}
+
+#endif // nssv_CPP11_OR_GREATER
+
+template< class CharT, class Traits, class Allocator >
+basic_string_view
+to_string_view( std::basic_string const & s )
+{
+ return basic_string_view( s.data(), s.size() );
+}
+
+}} // namespace nonstd::sv_lite
+
+#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+
+//
+// make types and algorithms available in namespace nonstd:
+//
+
+namespace nonstd {
+
+using sv_lite::basic_string_view;
+using sv_lite::string_view;
+using sv_lite::wstring_view;
+
+#if nssv_HAVE_WCHAR16_T
+using sv_lite::u16string_view;
+#endif
+#if nssv_HAVE_WCHAR32_T
+using sv_lite::u32string_view;
+#endif
+
+// literal "sv"
+
+using sv_lite::operator==;
+using sv_lite::operator!=;
+using sv_lite::operator<;
+using sv_lite::operator<=;
+using sv_lite::operator>;
+using sv_lite::operator>=;
+
+#if ! nssv_CONFIG_NO_STREAM_INSERTION
+using sv_lite::operator<<;
+#endif
+
+#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
+using sv_lite::to_string;
+using sv_lite::to_string_view;
+#endif
+
+} // namespace nonstd
+
+// 24.4.5 Hash support (C++11):
+
+// Note: The hash value of a string view object is equal to the hash value of
+// the corresponding string object.
+
+#if nssv_HAVE_STD_HASH
+
+#include
+
+namespace std {
+
+template<>
+struct hash< nonstd::string_view >
+{
+public:
+ std::size_t operator()( nonstd::string_view v ) const nssv_noexcept
+ {
+ return std::hash()( std::string( v.data(), v.size() ) );
+ }
+};
+
+template<>
+struct hash< nonstd::wstring_view >
+{
+public:
+ std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept
+ {
+ return std::hash()( std::wstring( v.data(), v.size() ) );
+ }
+};
+
+template<>
+struct hash< nonstd::u16string_view >
+{
+public:
+ std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept
+ {
+ return std::hash()( std::u16string( v.data(), v.size() ) );
+ }
+};
+
+template<>
+struct hash< nonstd::u32string_view >
+{
+public:
+ std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept
+ {
+ return std::hash()( std::u32string( v.data(), v.size() ) );
+ }
+};
+
+} // namespace std
+
+#endif // nssv_HAVE_STD_HASH
+
+nssv_RESTORE_WARNINGS()
+
+#endif // nssv_HAVE_STD_STRING_VIEW
+#endif // NONSTD_SV_LITE_H_INCLUDED
+/* end file simdjson/nonstd/string_view.hpp */
+SIMDJSON_POP_DISABLE_WARNINGS
+
+namespace std {
+ using string_view = nonstd::string_view;
+}
+#endif // SIMDJSON_HAS_STRING_VIEW
+#undef SIMDJSON_HAS_STRING_VIEW // We are not going to need this macro anymore.
+
+/// If EXPR is an error, returns it.
+#define SIMDJSON_TRY(EXPR) { auto _err = (EXPR); if (_err) { return _err; } }
+
+// Unless the programmer has already set SIMDJSON_DEVELOPMENT_CHECKS,
+// we want to set it under debug builds. We detect a debug build
+// under Visual Studio when the _DEBUG macro is set. Under the other
+// compilers, we use the fact that they define __OPTIMIZE__ whenever
+// they allow optimizations.
+// It is possible that this could miss some cases where SIMDJSON_DEVELOPMENT_CHECKS
+// is helpful, but the programmer can set the macro SIMDJSON_DEVELOPMENT_CHECKS.
+// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
+// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
+// set the __OPTIMIZE__ macro).
+// We make it so that if NDEBUG is defined, then SIMDJSON_DEVELOPMENT_CHECKS
+// is not defined, irrespective of the compiler.
+// We recommend that users set NDEBUG in release builds, so that
+// SIMDJSON_DEVELOPMENT_CHECKS is not defined in release builds by default,
+// irrespective of the compiler.
+#ifndef SIMDJSON_DEVELOPMENT_CHECKS
+#ifdef _MSC_VER
+// Visual Studio seems to set _DEBUG for debug builds.
+// We set SIMDJSON_DEVELOPMENT_CHECKS to 1 if _DEBUG is defined
+// and NDEBUG is not defined.
+#if defined(_DEBUG) && !defined(NDEBUG)
+#define SIMDJSON_DEVELOPMENT_CHECKS 1
+#endif // _DEBUG
+#else // _MSC_VER
+// All other compilers appear to set __OPTIMIZE__ to a positive integer
+// when the compiler is optimizing.
+// We only set SIMDJSON_DEVELOPMENT_CHECKS if both __OPTIMIZE__
+// and NDEBUG are not defined.
+// We recognize _DEBUG as overriding __OPTIMIZE__ so that if both
+// __OPTIMIZE__ and _DEBUG are defined, we still set SIMDJSON_DEVELOPMENT_CHECKS.
+#if ((!defined(__OPTIMIZE__) || defined(_DEBUG)) && !defined(NDEBUG))
+#define SIMDJSON_DEVELOPMENT_CHECKS 1
+#endif // __OPTIMIZE__
+#endif // _MSC_VER
+#endif // SIMDJSON_DEVELOPMENT_CHECKS
+
+// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
+// feature.
+
+#if SIMDJSON_CPLUSPLUS17
+// if we have C++, then fallthrough is a default attribute
+# define simdjson_fallthrough [[fallthrough]]
+// check if we have __attribute__ support
+#elif defined(__has_attribute)
+// check if we have the __fallthrough__ attribute
+#if __has_attribute(__fallthrough__)
+// we are good to go:
+# define simdjson_fallthrough __attribute__((__fallthrough__))
+#endif // __has_attribute(__fallthrough__)
+#endif // SIMDJSON_CPLUSPLUS17
+// on some systems, we simply do not have support for fallthrough, so use a default:
+#ifndef simdjson_fallthrough
+# define simdjson_fallthrough do {} while (0) /* fallthrough */
+#endif // simdjson_fallthrough
+
+#if SIMDJSON_DEVELOPMENT_CHECKS
+#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
+#else
+#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
+#endif
+
+#ifndef SIMDJSON_UTF8VALIDATION
+#define SIMDJSON_UTF8VALIDATION 1
+#endif
+
+#ifdef __has_include
+// How do we detect that a compiler supports vbmi2?
+// For sure if the following header is found, we are ok?
+#if __has_include()
+#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
+#endif
+#endif
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1920
+// Visual Studio 2019 and up support VBMI2 under x64 even if the header
+// avx512vbmi2intrin.h is not found.
+#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
+#endif
+#endif
+
+// By default, we allow AVX512.
+#ifndef SIMDJSON_AVX512_ALLOWED
+#define SIMDJSON_AVX512_ALLOWED 1
+#endif
+
+
+#ifndef __has_cpp_attribute
+#define simdjson_lifetime_bound
+#elif __has_cpp_attribute(msvc::lifetimebound)
+#define simdjson_lifetime_bound [[msvc::lifetimebound]]
+#elif __has_cpp_attribute(clang::lifetimebound)
+#define simdjson_lifetime_bound [[clang::lifetimebound]]
+#elif __has_cpp_attribute(lifetimebound)
+#define simdjson_lifetime_bound [[lifetimebound]]
+#else
+#define simdjson_lifetime_bound
+#endif
+#endif // SIMDJSON_COMMON_DEFS_H
+/* end file simdjson/common_defs.h */
+/* skipped duplicate #include "simdjson/compiler_check.h" */
+/* including simdjson/error.h: #include "simdjson/error.h" */
+/* begin file simdjson/error.h */
+#ifndef SIMDJSON_ERROR_H
+#define SIMDJSON_ERROR_H
+
+/* skipped duplicate #include "simdjson/base.h" */
+
+#include
+#include
+
+namespace simdjson {
+
+/**
+ * All possible errors returned by simdjson. These error codes are subject to change
+ * and not all simdjson kernel returns the same error code given the same input: it is not
+ * well defined which error a given input should produce.
+ *
+ * Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate
+ * to true as a Boolean.
+ */
+enum error_code {
+ SUCCESS = 0, ///< No error
+ CAPACITY, ///< This parser can't support a document that big
+ MEMALLOC, ///< Error allocating memory, most likely out of memory
+ TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
+ DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
+ STRING_ERROR, ///< Problem while parsing a string
+ T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
+ F_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'f'
+ N_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'n'
+ NUMBER_ERROR, ///< Problem while parsing a number
+ BIGINT_ERROR, ///< The integer value exceeds 64 bits
+ UTF8_ERROR, ///< the input is not valid UTF-8
+ UNINITIALIZED, ///< unknown error, or uninitialized document
+ EMPTY, ///< no structural element found
+ UNESCAPED_CHARS, ///< found unescaped characters in a string.
+ UNCLOSED_STRING, ///< missing quote at the end
+ UNSUPPORTED_ARCHITECTURE, ///< unsupported architecture
+ INCORRECT_TYPE, ///< JSON element has a different type than user expected
+ NUMBER_OUT_OF_RANGE, ///< JSON number does not fit in 64 bits
+ INDEX_OUT_OF_BOUNDS, ///< JSON array index too large
+ NO_SUCH_FIELD, ///< JSON field not found in object
+ IO_ERROR, ///< Error reading a file
+ INVALID_JSON_POINTER, ///< Invalid JSON pointer syntax
+ INVALID_URI_FRAGMENT, ///< Invalid URI fragment
+ UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
+ PARSER_IN_USE, ///< parser is already in use.
+ OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
+ INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
+ INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
+ SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
+ OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
+ TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
+ OUT_OF_CAPACITY, ///< The capacity was exceeded, we cannot allocate enough memory.
+ NUM_ERROR_CODES ///< Placeholder for end of error code list.
+};
+
+/**
+ * Some errors are fatal and invalidate the document. This function returns true if the
+ * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
+ * Once a fatal error is encountered, the on-demand document is no longer valid and
+ * processing should stop.
+ */
+ inline bool is_fatal(error_code error) noexcept;
+
+/**
+ * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
+ * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
+ * that was written while breaking some simdjson::ondemand requirement. They should not occur in released
+ * code after these issues were fixed.
+ */
+
+/**
+ * Get the error message for the given error code.
+ *
+ * dom::parser parser;
+ * dom::element doc;
+ * auto error = parser.parse("foo",3).get(doc);
+ * if (error) { printf("Error: %s\n", error_message(error)); }
+ *
+ * @return The error message.
+ */
+inline const char *error_message(error_code error) noexcept;
+
+/**
+ * Write the error message to the output stream
+ */
+inline std::ostream& operator<<(std::ostream& out, error_code error) noexcept;
+
+/**
+ * Exception thrown when an exception-supporting simdjson method is called
+ */
+struct simdjson_error : public std::exception {
+ /**
+ * Create an exception from a simdjson error code.
+ * @param error The error code
+ */
+ simdjson_error(error_code error) noexcept : _error{error} { }
+ /** The error message */
+ const char *what() const noexcept override { return error_message(error()); }
+ /** The error code */
+ error_code error() const noexcept { return _error; }
+private:
+ /** The error code that was used */
+ error_code _error;
+};
+
+namespace internal {
+
+/**
+ * The result of a simdjson operation that could fail.
+ *
+ * IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base as a base class
+ * to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand
+ * implementation_simdjson_result_base is also modified.
+ *
+ * Gives the option of reading error codes, or throwing an exception by casting to the desired result.
+ *
+ * This is a base class for implementations that want to add functions to the result type for
+ * chaining.
+ *
+ * Override like:
+ *
+ * struct simdjson_result : public internal::simdjson_result_base {
+ * simdjson_result() noexcept : internal::simdjson_result_base() {}
+ * simdjson_result(error_code error) noexcept : internal::simdjson_result_base(error) {}
+ * simdjson_result(T &&value) noexcept : internal::simdjson_result_base(std::forward(value)) {}
+ * simdjson_result(T &&value, error_code error) noexcept : internal::simdjson_result_base(value, error) {}
+ * // Your extra methods here
+ * }
+ *
+ * Then any method returning simdjson_result will be chainable with your methods.
+ */
+template
+struct simdjson_result_base : protected std::pair {
+
+ /**
+ * Create a new empty result with error = UNINITIALIZED.
+ */
+ simdjson_inline simdjson_result_base() noexcept;
+
+ /**
+ * Create a new error result.
+ */
+ simdjson_inline simdjson_result_base(error_code error) noexcept;
+
+ /**
+ * Create a new successful result.
+ */
+ simdjson_inline simdjson_result_base(T &&value) noexcept;
+
+ /**
+ * Create a new result with both things (use if you don't want to branch when creating the result).
+ */
+ simdjson_inline simdjson_result_base(T &&value, error_code error) noexcept;
+
+ /**
+ * Move the value and the error to the provided variables.
+ *
+ * @param value The variable to assign the value to. May not be set if there is an error.
+ * @param error The variable to assign the error to. Set to SUCCESS if there is no error.
+ */
+ simdjson_inline void tie(T &value, error_code &error) && noexcept;
+
+ /**
+ * Move the value to the provided variable.
+ *
+ * @param value The variable to assign the value to. May not be set if there is an error.
+ */
+ simdjson_inline error_code get(T &value) && noexcept;
+
+ /**
+ * The error.
+ */
+ simdjson_inline error_code error() const noexcept;
+
+ /**
+ * Whether there is a value.
+ */
+ simdjson_inline bool has_value() const noexcept;
+#if SIMDJSON_EXCEPTIONS
+
+ /**
+ * Dereference operator to access the contained value.
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T& operator*() & noexcept(false);
+ simdjson_inline T&& operator*() && noexcept(false);
+ /**
+ * Arrow operator to access members of the contained value.
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T* operator->() noexcept(false);
+ simdjson_inline const T* operator->() const noexcept(false);
+
+ /**
+ * Get the result value.
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T& value() & noexcept(false);
+
+ /**
+ * Take the result value (move it).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T&& value() && noexcept(false);
+
+ /**
+ * Take the result value (move it).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T&& take_value() && noexcept(false);
+
+ /**
+ * Cast to the value (will throw on error).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline operator T&&() && noexcept(false);
+
+#endif // SIMDJSON_EXCEPTIONS
+
+ /**
+ * Get the result value. This function is safe if and only
+ * the error() method returns a value that evaluates to false.
+ * We discourage the use of value_unsafe().
+ *
+ * The recommended pattern is:
+ *
+ * T value; // where T is the type
+ * auto error = result.get(value);
+ * if (error) {
+ * // handle error
+ * }
+ *
+ * Or you may call 'value()' which will raise an exception
+ * in case of error:
+ *
+ * T value = result.value();
+ */
+ simdjson_inline const T& value_unsafe() const& noexcept;
+
+ /**
+ * Take the result value (move it). This function is safe if and only
+ * the error() method returns a value that evaluates to false.
+ * We discourage the use of value_unsafe().
+ *
+ * The recommended pattern is:
+ *
+ * T value; // where T is the type
+ * auto error = result.get(value);
+ * if (error) {
+ * // handle error, return, exit, abort
+ * } else {
+ * // use value here.
+ * }
+ *
+ * Or you may call 'value()' which will raise an exception
+ * in case of error:
+ *
+ * T value = result.value();
+ */
+ simdjson_inline T&& value_unsafe() && noexcept;
+
+ using value_type = T;
+ using error_type = error_code;
+}; // struct simdjson_result_base
+
+} // namespace internal
+
+/**
+ * The result of a simdjson operation that could fail.
+ *
+ * Gives the option of reading error codes, or throwing an exception by casting to the desired result.
+ */
+template
+struct simdjson_result : public internal::simdjson_result_base {
+
+ /**
+ * @private Create a new empty result with error = UNINITIALIZED.
+ */
+ simdjson_inline simdjson_result() noexcept;
+ /**
+ * @private Create a new successful result.
+ */
+ simdjson_inline simdjson_result(T &&value) noexcept;
+ /**
+ * @private Create a new error result.
+ */
+ simdjson_inline simdjson_result(error_code error_code) noexcept;
+ /**
+ * @private Create a new result with both things (use if you don't want to branch when creating the result).
+ */
+ simdjson_inline simdjson_result(T &&value, error_code error) noexcept;
+
+ /**
+ * Move the value and the error to the provided variables.
+ *
+ * @param value The variable to assign the value to. May not be set if there is an error.
+ * @param error The variable to assign the error to. Set to SUCCESS if there is no error.
+ */
+ simdjson_inline void tie(T &value, error_code &error) && noexcept;
+
+ /**
+ * Move the value to the provided variable.
+ *
+ * @param value The variable to assign the value to. May not be set if there is an error.
+ */
+ simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
+
+ /**
+ * Copy the value to a provided std::string, only enabled for std::string_view.
+ *
+ * @param value The variable to assign the value to. May not be set if there is an error.
+ */
+ template
+ simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept {
+ static_assert(std::is_same::value, "SFINAE");
+ std::string_view v;
+ error_code error = std::forward>(*this).get(v);
+ if (!error) {
+ value.assign(v.data(), v.size());
+ }
+ return error;
+ }
+
+ /**
+ * The error.
+ */
+ simdjson_inline error_code error() const noexcept;
+
+
+
+#if SIMDJSON_EXCEPTIONS
+ using internal::simdjson_result_base::operator*;
+ using internal::simdjson_result_base::operator->;
+ /**
+ * Get the result value.
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T& value() & noexcept(false);
+
+ /**
+ * Take the result value (move it).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T&& value() && noexcept(false);
+
+ /**
+ * Take the result value (move it).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline T&& take_value() && noexcept(false);
+
+ /**
+ * Cast to the value (will throw on error).
+ *
+ * @throw simdjson_error if there was an error.
+ */
+ simdjson_inline operator T&&() && noexcept(false);
+#endif // SIMDJSON_EXCEPTIONS
+
+ /**
+ * Get the result value. This function is safe if and only
+ * the error() method returns a value that evaluates to false.
+ */
+ simdjson_inline const T& value_unsafe() const& noexcept;
+
+ /**
+ * Take the result value (move it). This function is safe if and only
+ * the error() method returns a value that evaluates to false.
+ */
+ simdjson_inline T&& value_unsafe() && noexcept;
+
+ using value_type = T;
+ using error_type = error_code;
+}; // struct simdjson_result
+
+#if SIMDJSON_EXCEPTIONS
+
+template
+inline std::ostream& operator<<(std::ostream& out, simdjson_result value) { return out << value.value(); }
+#endif // SIMDJSON_EXCEPTIONS
+
+#ifndef SIMDJSON_DISABLE_DEPRECATED_API
+/**
+ * @deprecated This is an alias and will be removed, use error_code instead
+ */
+using ErrorValues [[deprecated("This is an alias and will be removed, use error_code instead")]] = error_code;
+
+/**
+ * @deprecated Error codes should be stored and returned as `error_code`, use `error_message()` instead.
+ */
+[[deprecated("Error codes should be stored and returned as `error_code`, use `error_message()` instead.")]]
+inline const std::string error_message(int error) noexcept;
+#endif // SIMDJSON_DISABLE_DEPRECATED_API
+} // namespace simdjson
+
+#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_CONCEPTS
+
+#include
+#include
+
+namespace simdjson {
+namespace concepts {
+
+namespace details {
+#define SIMDJSON_IMPL_CONCEPT(name, method) \
+ template \
+ concept supports_##name = !std::is_const_v && requires { \
+ typename std::remove_cvref_t::value_type; \
+ requires requires(typename std::remove_cvref_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
+
+template
+concept is_pair = requires { typename T::first_type; typename T::second_type; } &&
+ std::same_as>;
+template
+concept string_view_like = std::is_convertible_v &&
+ !std::is_convertible_v;
+
+template
+concept constructible_from_string_view = std::is_constructible_v
+ && !std::is_same_v
+ && std::is_default_constructible_v;
+
+template
+concept string_view_keyed_map = string_view_like
+ && requires(std::remove_cvref_t& m, typename M::key_type sv, typename M::mapped_type v) {
+ { m.emplace(sv, v) } -> std::same_as>;
+};
+
+/// Check if T is a container that we can append to, including:
+/// std::vector, std::deque, std::list, std::string, ...
+template
+concept appendable_containers =
+ (details::supports_emplace_back || details::supports_emplace ||
+ details::supports_push_back || details::supports_push ||
+ details::supports_add || details::supports_append ||
+ details::supports_insert) && !string_view_keyed_map;
+
+/// Insert into the container however possible
+template
+constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
+ if constexpr (details::supports_emplace_back) {
+ return vec.emplace_back(std::forward(args)...);
+ } else if constexpr (details::supports_emplace) {
+ return vec.emplace(std::forward(args)...);
+ } else if constexpr (details::supports_push_back) {
+ return vec.push_back(std::forward(args)...);
+ } else if constexpr (details::supports_push) {
+ return vec.push(std::forward(args)...);
+ } else if constexpr (details::supports_add) {
+ return vec.add(std::forward(args)...);
+ } else if constexpr (details::supports_append) {
+ return vec.append(std::forward(args)...);
+ } else if constexpr (details::supports_insert) {
+ return vec.insert(std::forward(args)...);
+ } else if constexpr (details::supports_op_append