From 2507e348833fde120a1022b99735de923b14c744 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 15 May 2025 16:36:01 -0400 Subject: [PATCH] Prepare for streaming interface --- src/test.cpp | 61 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/test.cpp b/src/test.cpp index d6beddc..edc4124 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -415,15 +415,30 @@ private: // Table-based ll(1) parser that doesn't handle escaping and treats numbers as // [0-9.]+. Could be adapted to have a streaming interface. Uses O(1) memory. struct Parser2 { - Parser2(char *buf, int len, const Callbacks *callbacks, void *data) - : buf(buf), bufEnd(buf + len), callbacks(callbacks), data(data) {} + Parser2(const Callbacks *callbacks, void *data) + : callbacks(callbacks), data(data) {} - // Returns false to reject - [[nodiscard]] bool parse() { - if (push({N_VALUE}) != S_OK) { - return false; + void prime(char *buf, int len) { + this->buf = buf; + this->bufEnd = buf + len; + } + + enum Status { + // Accept input + S_OK, + // Consumed available input. Prime more and parse again + S_AGAIN, + // Invalid json + S_REJECT, + // json is too deeply nested + S_OVERFLOW, + }; + + [[nodiscard]] Status parse() { + if (Status s = push({N_VALUE})) { + return s; } - return keepGoing(this) == S_OK; + return keepGoing(this); } Parser2(Parser2 const &) = delete; @@ -433,13 +448,6 @@ struct Parser2 { static constexpr int kMaxStackSize = 1 << 10; - enum Status { - S_OK, - S_AGAIN, - S_REJECT, - S_OVERFLOW, - }; - private: // Helpers void maybeSkipWs() { @@ -632,8 +640,8 @@ private: /*N_OBJECT_MAYBE_CONTINUE*/ objectContinue, }; - char *buf; - char *bufEnd; + char *buf = nullptr; + char *bufEnd = nullptr; int len() const { return bufEnd - buf; } const Callbacks *const callbacks; void *const data; @@ -724,13 +732,23 @@ TEST_CASE("parser2") { Callbacks c = printCallbacks(); { auto copy = json; - Parser2 parser(copy.data(), copy.length(), &c, nullptr); - CHECK(parser.parse()); + Parser2 parser(&c, nullptr); + parser.prime(copy.data(), copy.length()); + CHECK(parser.parse() == Parser2::S_OK); } { std::string copy = "{\"x\": [], \"y\": {}}"; - Parser2 parser(copy.data(), copy.length(), &c, nullptr); - CHECK(parser.parse()); + Parser2 parser(&c, nullptr); + parser.prime(copy.data(), copy.length()); + CHECK(parser.parse() == Parser2::S_OK); + } + { + std::string copy = "true"; + Parser2 parser(&c, nullptr); + parser.prime(copy.data(), 2); + CHECK(parser.parse() == Parser2::S_AGAIN); + parser.prime(copy.data() + 2, 2); + CHECK(parser.parse() == Parser2::S_OK); } } @@ -753,7 +771,8 @@ TEST_CASE("bench2") { bench.unit("byte"); bench.run("parser2", [&]() { auto copy = json; - Parser2 parser(copy.data(), copy.length(), &c, nullptr); + Parser2 parser(&c, nullptr); + parser.prime(copy.data(), copy.length()); bench.doNotOptimizeAway(parser.parse()); }); }