mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 16:35:40 +02:00
Keep the parent links inside a detached jsonpull subtree
json_read_tree() and json_disconnect() cleared both back-pointers on every node of the subtree they handed out. Clearing `parser` throughout is necessary -- the json_pull can be destroyed while the subtree lives on, so a surviving `parser` would dangle -- but clearing `parent` throughout cost more than it bought. `parent` is a non-owning raw pointer, so keeping it cannot form a reference cycle or keep anything alive; there is nothing to leak. And within a detached subtree it refers to nodes the caller now owns as a single unit, so it stays valid for exactly as long as the subtree itself. Clearing it only made the tree unwalkable upwards, and made json_free() and json_disconnect() silently no-ops on interior nodes of a detached tree, since both find a node's owner through o->parent. So clear `parser` everywhere and clear `parent` on the detached root alone, which is the one that pointed out of the subtree at a node the parser still owns. Split the old clear_back_pointers() into clear_parser_pointers() plus a detach_subtree() wrapper that adds the root's `parent`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KNxyHKasyWrWcvre2yK4r
This commit is contained in:
+21
-13
@@ -78,10 +78,14 @@ struct json_entry {
|
||||
//
|
||||
// Children are owned by their parent (via std::vector<json_object_ptr>
|
||||
// inside json_array / json_hash); the raw `parent` and `parser`
|
||||
// back-pointers stay valid as long as the node is attached to the tree.
|
||||
// json_disconnect() splices a node out of its parent and walks the
|
||||
// detached subtree clearing those back-pointers so the subtree can
|
||||
// outlive the original parser.
|
||||
// back-pointers own nothing. json_disconnect() splices a node out of its
|
||||
// parent and walks the detached subtree clearing every `parser` pointer,
|
||||
// so the subtree can outlive the original parser. The `parent` pointers
|
||||
// within the subtree survive -- they refer to nodes the caller now owns
|
||||
// as one unit -- so a detached tree can still be walked upwards, and
|
||||
// json_free() / json_disconnect() still work on its interior nodes. Only
|
||||
// the detached root's `parent`, which pointed out of the subtree, is
|
||||
// cleared.
|
||||
//
|
||||
// json_object intentionally has no virtual functions and no virtual
|
||||
// destructor; the json_object_ptr deleter (see below in this header)
|
||||
@@ -364,10 +368,11 @@ json_object *json_read_separators(json_pull_ptr &j, json_separator_callback cb,
|
||||
|
||||
// json_read_tree drains the next top-level value out of the parser
|
||||
// and hands ownership to the caller. After it returns, jp->root is
|
||||
// empty, the parent/parser back-pointers throughout the subtree have
|
||||
// been cleared, and the caller's json_object_ptr is the only thing
|
||||
// keeping the tree alive. The returned tree can outlive the
|
||||
// json_pull it was parsed from.
|
||||
// empty, every `parser` back-pointer in the subtree has been cleared
|
||||
// (as has the root's `parent`), and the caller's json_object_ptr is the
|
||||
// only thing keeping the tree alive. The returned tree can outlive the
|
||||
// json_pull it was parsed from, and stays internally navigable: the
|
||||
// `parent` pointers between its nodes are left intact.
|
||||
json_object_ptr json_read_tree(json_pull_ptr &j);
|
||||
|
||||
// json_free splices `o` out of its parent (if any), or clears the
|
||||
@@ -377,11 +382,14 @@ json_object_ptr json_read_tree(json_pull_ptr &j);
|
||||
void json_free(json_object *o);
|
||||
|
||||
// Splice `o` out of its parent's array/object (or out of the parser's
|
||||
// root), walk the detached subtree clearing parent/parser back-pointers,
|
||||
// and return ownership of the subtree to the caller as a
|
||||
// json_object_ptr. After this returns, the parser no longer references
|
||||
// any node in the subtree, and the subtree can outlive the original
|
||||
// parser.
|
||||
// root), walk the detached subtree clearing every `parser` back-pointer
|
||||
// (and the root's `parent`, which pointed out of the subtree), and return
|
||||
// ownership of the subtree to the caller as a json_object_ptr. After this
|
||||
// returns, the parser no longer references any node in the subtree, and
|
||||
// the subtree can outlive the original parser. The `parent` pointers
|
||||
// among the subtree's own nodes are preserved, so the detached tree can
|
||||
// still be walked upwards and json_free() / json_disconnect() still work
|
||||
// on its interior nodes.
|
||||
json_object_ptr json_disconnect(json_object *o);
|
||||
|
||||
// Look up `s` in the hash `o`. Returns a borrowed pointer; ownership
|
||||
|
||||
Reference in New Issue
Block a user