summaryrefslogtreecommitdiff
path: root/expat/lib/xmlparse.c
diff options
context:
space:
mode:
authorSebastian Pipping <sebastian@pipping.org>2022-02-20 15:57:54 +0100
committerGitHub <noreply@github.com>2022-02-20 15:57:54 +0100
commit9288cd5474bf6d3d0c037c247f9581d5e4df5097 (patch)
treeda9bf35d91800e3a3bb8e3d82defccdfa5d2bdb4 /expat/lib/xmlparse.c
parent97a4840578693a346e79302909b67d97492e1880 (diff)
parent2722201a5baffbbe5c4942a42dd1fa21b8d22ccc (diff)
downloadlibexpat-git-9288cd5474bf6d3d0c037c247f9581d5e4df5097.tar.gz
Merge pull request #566 from ferivoz/model-regression
Fix build_model regression
Diffstat (limited to 'expat/lib/xmlparse.c')
-rw-r--r--expat/lib/xmlparse.c79
1 files changed, 47 insertions, 32 deletions
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index c479a258..84885b5a 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -7373,39 +7373,58 @@ build_model(XML_Parser parser) {
*
* The iterative approach works as follows:
*
- * - We use space in the target array for building a temporary stack structure
- * while that space is still unused.
- * The stack grows from the array's end downwards and the "actual data"
- * grows from the start upwards, sequentially.
- * (Because stack grows downwards, pushing onto the stack is a decrement
- * while popping off the stack is an increment.)
+ * - We have two writing pointers, both walking up the result array; one does
+ * the work, the other creates "jobs" for its colleague to do, and leads
+ * the way:
*
- * - A stack element appears as a regular XML_Content node on the outside,
- * but only uses a single field -- numchildren -- to store the source
- * tree node array index. These are the breadcrumbs leading the way back
- * during pre-order (node first) depth-first traversal.
+ * - The faster one, pointer jobDest, always leads and writes "what job
+ * to do" by the other, once they reach that place in the
+ * array: leader "jobDest" stores the source node array index (relative
+ * to array dtd->scaffold) in field "numchildren".
*
- * - The reason we know the stack will never grow into (or overlap with)
- * the area with data of value at the start of the array is because
- * the overall number of elements to process matches the size of the array,
- * and the sum of fully processed nodes and yet-to-be processed nodes
- * on the stack, cannot be more than the total number of nodes.
- * It is possible for the top of the stack and the about-to-write node
- * to meet, but that is safe because we get the source index out
- * before doing any writes on that node.
+ * - The slower one, pointer dest, looks at the value stored in the
+ * "numchildren" field (which actually holds a source node array index
+ * at that time) and puts the real data from dtd->scaffold in.
+ *
+ * - Before the loop starts, jobDest writes source array index 0
+ * (where the root node is located) so that dest will have something to do
+ * when it starts operation.
+ *
+ * - Whenever nodes with children are encountered, jobDest appends
+ * them as new jobs, in order. As a result, tree node siblings are
+ * adjacent in the resulting array, for example:
+ *
+ * [0] root, has two children
+ * [1] first child of 0, has three children
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ * [2] second child of 0, does not have children
+ *
+ * Or (the same data) presented in flat array view:
+ *
+ * [0] root, has two children
+ *
+ * [1] first child of 0, has three children
+ * [2] second child of 0, does not have children
+ *
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ *
+ * - The algorithm repeats until all target array indices have been processed.
*/
XML_Content *dest = ret; /* tree node writing location, moves upwards */
XML_Content *const destLimit = &ret[dtd->scaffCount];
- XML_Content *const stackBottom = &ret[dtd->scaffCount];
- XML_Content *stackTop = stackBottom; /* i.e. stack is initially empty */
+ XML_Content *jobDest = ret; /* next free writing location in target array */
str = (XML_Char *)&ret[dtd->scaffCount];
- /* Push source tree root node index onto the stack */
- (--stackTop)->numchildren = 0;
+ /* Add the starting job, the root node (index 0) of the source tree */
+ (jobDest++)->numchildren = 0;
for (; dest < destLimit; dest++) {
- /* Pop source tree node index off the stack */
- const int src_node = (int)(stackTop++)->numchildren;
+ /* Retrieve source tree array index from job storage */
+ const int src_node = (int)dest->numchildren;
/* Convert item */
dest->type = dtd->scaffold[src_node].type;
@@ -7427,16 +7446,12 @@ build_model(XML_Parser parser) {
int cn;
dest->name = NULL;
dest->numchildren = dtd->scaffold[src_node].childcnt;
- dest->children = &dest[1];
+ dest->children = jobDest;
- /* Push children to the stack
- * in a way where the first child ends up at the top of the
- * (downwards growing) stack, in order to be processed first. */
- stackTop -= dest->numchildren;
+ /* Append scaffold indices of children to array */
for (i = 0, cn = dtd->scaffold[src_node].firstchild;
- i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) {
- (stackTop + i)->numchildren = (unsigned int)cn;
- }
+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
+ (jobDest++)->numchildren = (unsigned int)cn;
}
}