Prepare for streaming interface

This commit is contained in:
2025-05-15 16:36:01 -04:00
parent 8720220303
commit 2507e34883

View File

@@ -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;
}
return keepGoing(this) == S_OK;
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);
}
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());
});
}