Move parser-only expect state out of json_object

`expect` was only meaningful while the parser was building a container,
and only ever read or written from jsonpull.cpp itself; once parsing
finished it was dead weight on every JSON_ARRAY and JSON_HASH (and
present-but-unused on every primitive too). Move it into the parser's
container stack, alongside the shared_ptr to the container it pertains
to:

    struct json_pull::parse_frame {
        json_object_ptr container;
        json_type       expect;
    };
    std::vector<parse_frame> container_stack;

The base class now only carries data-model state (parent, parser, type).
No external caller depended on `expect`, so no sweep was needed outside
jsonpull.cpp.

This change does not, in itself, shrink any json_object: the 4-byte
`expect` field used to live at offset 20 inside the base, where it was
already being eaten by alignment padding for the 8-byte-aligned first
member of every subclass (std::string, std::vector, double). The win is
in the data model, not the byte count -- the 4-byte hole is still
there, but it is now available for a future subclass whose first member
is small enough to slot into it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Erica Fischer
2026-05-30 17:49:19 -07:00
co-authored by Cursor
parent 4d9a48c3d4
commit bd90f0b4fe
2 changed files with 46 additions and 39 deletions
+11 -5
View File
@@ -72,7 +72,6 @@ struct json_object {
json_pull *parser = nullptr;
json_type type;
int expect = 0; // used by the parser on JSON_ARRAY / JSON_HASH nodes
json_object(json_type t) : type(t) {}
json_object(json_type t, json_object *p, json_pull *pl) : parent(p), parser(pl), type(t) {}
@@ -190,10 +189,17 @@ struct json_pull {
ssize_t buffer_head = 0;
// Stack of currently-open containers; the top is the innermost container
// being parsed. Replaces the previous single `container` pointer / parent
// walk, which previously required enable_shared_from_this<json_object>
// on every json_object instance (16 extra bytes per node).
std::vector<json_object_ptr> container_stack;
// being parsed. Each frame also remembers what token is expected next
// (an item, a comma, a key, a colon, or a value). This stack is the
// only place the parser-only `expect` state lives, so it does not
// pollute json_object once parsing finishes. Replaces the previous
// single `container` pointer / parent walk, which previously required
// enable_shared_from_this<json_object> on every json_object instance.
struct parse_frame {
json_object_ptr container;
json_type expect;
};
std::vector<parse_frame> container_stack;
json_object_ptr root;
std::string number_buffer;