parser FEATURE support for faster ordered parsing
diff --git a/src/parser_data.h b/src/parser_data.h
index 6b4aeea..47759f1 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -151,6 +151,12 @@
#define LYD_PARSE_LYB_MOD_UPDATE 0x100000 /**< Only for LYB format, allow parsing data printed using a specific module
revision to be loaded even with a module with the same name but newer
revision. */
+#define LYD_PARSE_ORDERED 0x200000 /**< Do not search for the correct place of each node but instead expect
+ that the nodes are being parsed in the correct schema-based order,
+ which is always true if the data were printed by libyang and not
+ modified manually. If this flag is used incorrectly (for unordered data),
+ the behavior is undefined and most functions executed with these
+ data will not work correctly. */
#define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */
diff --git a/src/parser_json.c b/src/parser_json.c
index ca11b31..ebb1449 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -847,18 +847,20 @@
}
/**
- * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing to the first child node.
+ * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing
+ * to the first child node.
*
* @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
- * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
- * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
+ * @param[in,out] first_p Pointer to the first sibling node in case of top-level.
+ * @param[in,out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
+ * @param[in] last If set, always insert at the end.
*/
static void
-lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
+lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p, ly_bool last)
{
if (*node_p) {
/* insert, keep first pointer correct */
- lyd_insert_node(parent ? &parent->node : NULL, first_p, *node_p);
+ lyd_insert_node(parent ? &parent->node : NULL, first_p, *node_p, last);
if (first_p) {
if (parent) {
*first_p = parent->child;
@@ -971,7 +973,7 @@
/* continue with the next instance */
assert(node_p);
- lydjson_maintain_children(parent, first_p, node_p);
+ lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p);
LY_CHECK_RET(ret);
}
@@ -1331,7 +1333,8 @@
/* process all the values/objects */
do {
- lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
+ lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node,
+ lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
ret = lydjson_parse_instance(lydctx, (struct lyd_node_inner *)parent, first_p, snode, name, name_len,
prefix, prefix_len, &status, &node);
@@ -1383,7 +1386,8 @@
}
/* finally connect the parsed node */
- lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
+ lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node,
+ lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
/* rememeber a successfully parsed node */
if (parsed) {
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 3c8578f..78496fc 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -957,7 +957,7 @@
}
/* insert, keep first pointer correct */
- lyd_insert_node(parent, first_p, node);
+ lyd_insert_node(parent, first_p, node, lybctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
while (!parent && (*first_p)->prev->next) {
*first_p = (*first_p)->prev;
}
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 3e46ad4..787d29f 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -696,7 +696,7 @@
}
/* insert, keep first pointer correct */
- lyd_insert_node(parent, first_p, node);
+ lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
while (!parent && (*first_p)->prev->next) {
*first_p = (*first_p)->prev;
}
@@ -817,7 +817,7 @@
r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
if (r == LY_SUCCESS) {
/* insert */
- lyd_insert_node(*envp, NULL, child);
+ lyd_insert_node(*envp, NULL, child, 0);
/* NETCONF action */
*int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
@@ -871,7 +871,7 @@
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
/* insert */
- lyd_insert_node(*envp, NULL, child);
+ lyd_insert_node(*envp, NULL, child, 0);
/* validate value */
/* TODO validate child->value as yang:date-and-time */
@@ -954,7 +954,7 @@
}
/* insert */
- lyd_insert_node(parent, NULL, child);
+ lyd_insert_node(parent, NULL, child, 1);
cleanup:
lyd_free_attr_siblings(xmlctx->ctx, attr);
@@ -1080,7 +1080,7 @@
LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
/* insert */
- lyd_insert_node(parent, NULL, child);
+ lyd_insert_node(parent, NULL, child, 1);
}
return LY_SUCCESS;
@@ -1255,7 +1255,7 @@
LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
/* insert */
- lyd_insert_node(parent, NULL, child);
+ lyd_insert_node(parent, NULL, child, 1);
}
return LY_SUCCESS;
@@ -1299,7 +1299,7 @@
r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
if (r == LY_SUCCESS) {
/* insert */
- lyd_insert_node(*envp, NULL, child);
+ lyd_insert_node(*envp, NULL, child, 1);
/* finish child parsing */
if (xmlctx->status != LYXML_ELEM_CLOSE) {
@@ -1330,7 +1330,7 @@
}
/* insert */
- lyd_insert_node(*envp, NULL, child);
+ lyd_insert_node(*envp, NULL, child, 1);
/* parse all children of "rpc-error" */
LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
diff --git a/src/tree_data.c b/src/tree_data.c
index 1230f8d..93d3da7 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -736,7 +736,7 @@
/* create and insert all the keys */
LY_ARRAY_FOR(predicates, u) {
LY_CHECK_GOTO(ret = lyd_create_term2(predicates[u].key, &predicates[u].value, &key), cleanup);
- lyd_insert_node(list, NULL, key);
+ lyd_insert_node(list, NULL, key, 0);
}
/* hash having all the keys */
@@ -882,7 +882,7 @@
LY_CHECK_RET(lyd_create_inner(schema, &ret));
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 0);
}
if (node) {
@@ -967,11 +967,11 @@
rc = lyd_create_term(key_s, key_val, key_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
LY_CHECK_GOTO(rc, cleanup);
- lyd_insert_node(ret, NULL, key);
+ lyd_insert_node(ret, NULL, key, 1);
}
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 0);
}
cleanup:
@@ -1063,7 +1063,7 @@
rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
NULL, &key);
LY_CHECK_GOTO(rc, cleanup);
- lyd_insert_node(ret, NULL, key);
+ lyd_insert_node(ret, NULL, key, 1);
}
cleanup:
@@ -1105,7 +1105,7 @@
LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
}
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 0);
}
if (node) {
@@ -1149,7 +1149,7 @@
rc = lyd_create_term(schema, value, value_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret);
LY_CHECK_RET(rc);
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 0);
}
if (node) {
@@ -1226,7 +1226,7 @@
LY_CHECK_RET(lyd_create_any(schema, value, value_type, use_value, &ret));
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 0);
}
if (node) {
@@ -1361,7 +1361,7 @@
LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), prefix, prefix ? strlen(prefix) : 0, module_name,
strlen(module_name), value, strlen(value), NULL, LY_VALUE_JSON, NULL, 0, &ret));
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 1);
}
if (node) {
@@ -1388,7 +1388,7 @@
LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), prefix, prefix ? strlen(prefix) : 0, module_ns,
strlen(module_ns), value, strlen(value), NULL, LY_VALUE_XML, NULL, 0, &ret));
if (parent) {
- lyd_insert_node(parent, NULL, ret);
+ lyd_insert_node(parent, NULL, ret, 1);
}
if (node) {
@@ -1982,10 +1982,10 @@
if (cur_parent) {
/* connect to the parent */
- lyd_insert_node(cur_parent, NULL, node);
+ lyd_insert_node(cur_parent, NULL, node, 0);
} else if (parent) {
/* connect to top-level siblings */
- lyd_insert_node(NULL, &parent, node);
+ lyd_insert_node(NULL, &parent, node, 0);
}
next_iter:
@@ -2098,7 +2098,7 @@
/* create default NP container */
LY_CHECK_RET(lyd_create_inner(iter, &node));
node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
- lyd_insert_node(parent, first, node);
+ lyd_insert_node(parent, first, node, 0);
if (lysc_has_when(iter) && node_when) {
/* remember to resolve when */
@@ -2132,7 +2132,7 @@
return ret;
}
node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
- lyd_insert_node(parent, first, node);
+ lyd_insert_node(parent, first, node, 0);
if (lysc_has_when(iter) && node_when) {
/* remember to resolve when */
@@ -2164,7 +2164,7 @@
return ret;
}
node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
- lyd_insert_node(parent, first, node);
+ lyd_insert_node(parent, first, node, 0);
if (lysc_has_when(iter) && node_when) {
/* remember to resolve when */
@@ -2526,7 +2526,7 @@
}
void
-lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node)
+lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node, ly_bool last)
{
struct lyd_node *anchor, *first_sibling;
@@ -2542,19 +2542,29 @@
/* get first sibling */
first_sibling = parent ? lyd_child(parent) : *first_sibling_p;
- /* find the anchor, our next node, so we can insert before it */
- anchor = lyd_insert_get_next_anchor(first_sibling, node);
+ if (last) {
+ /* no next anchor */
+ anchor = NULL;
+ } else {
+ /* find the anchor, our next node, so we can insert before it */
+ anchor = lyd_insert_get_next_anchor(first_sibling, node);
+ }
+
if (anchor) {
+ /* insert before the anchor */
lyd_insert_before_node(anchor, node);
if (!parent && (*first_sibling_p == anchor)) {
/* move first sibling */
*first_sibling_p = node;
}
} else if (first_sibling) {
+ /* insert as the last node */
lyd_insert_after_node(first_sibling->prev, node);
} else if (parent) {
+ /* insert as the only child */
lyd_insert_only_child(parent, node);
} else {
+ /* insert as the only sibling */
*first_sibling_p = node;
}
@@ -2639,7 +2649,7 @@
while (node) {
iter = node->next;
lyd_unlink_tree(node);
- lyd_insert_node(parent, NULL, node);
+ lyd_insert_node(parent, NULL, node, 0);
node = iter;
}
return LY_SUCCESS;
@@ -2673,7 +2683,7 @@
iter = node->next;
lyd_unlink_tree(node);
- lyd_insert_node(NULL, &sibling, node);
+ lyd_insert_node(NULL, &sibling, node, 0);
node = iter;
}
@@ -3464,7 +3474,7 @@
}
/* insert */
- lyd_insert_node(parent, first, dup);
+ lyd_insert_node(parent, first, dup, 0);
if (dup_p) {
*dup_p = dup;
@@ -3728,7 +3738,7 @@
}
/* insert */
- lyd_insert_node(parent_trg, first_trg, dup_src);
+ lyd_insert_node(parent_trg, first_trg, dup_src, 0);
if (first_inst) {
/* remember not to find this instance next time */
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 7a63e5f..fb5e4af 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -234,8 +234,9 @@
* @param[in] parent Parent to insert into, NULL for top-level sibling.
* @param[in,out] first_sibling First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
* @param[in] node Individual node (without siblings) to insert.
+ * @param[in] last If set, do not search for the correct anchor but always insert at the end.
*/
-void lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node);
+void lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node, ly_bool last);
/**
* @brief Insert a metadata (last) into a parent
diff --git a/src/validation.c b/src/validation.c
index e206225..6b2c841 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -1649,7 +1649,7 @@
lyd_val_op_merge_find(op_tree, op_node, dep_tree, &op_subtree, &tree_sibling, &tree_parent);
op_parent = lyd_parent(op_subtree);
lyd_unlink_tree(op_subtree);
- lyd_insert_node(tree_parent, &tree_sibling, op_subtree);
+ lyd_insert_node(tree_parent, &tree_sibling, op_subtree, 0);
if (!dep_tree) {
dep_tree = tree_sibling;
}
@@ -1693,7 +1693,7 @@
/* restore operation tree */
lyd_unlink_tree(op_subtree);
if (op_parent) {
- lyd_insert_node(op_parent, NULL, op_subtree);
+ lyd_insert_node(op_parent, NULL, op_subtree, 0);
}
ly_set_erase(&node_when, NULL);
diff --git a/tests/perf/perf.c b/tests/perf/perf.c
index d5a95ca..893a220 100644
--- a/tests/perf/perf.c
+++ b/tests/perf/perf.c
@@ -436,13 +436,14 @@
static LY_ERR
test_parse_xml_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_XML, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_XML, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+ ts_start, ts_end);
}
static LY_ERR
test_parse_xml_file_no_validate_format(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_XML, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_XML, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
}
static LY_ERR
@@ -454,13 +455,14 @@
static LY_ERR
test_parse_json_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_JSON, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_JSON, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+ ts_start, ts_end);
}
static LY_ERR
test_parse_json_file_no_validate_format(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_JSON, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_JSON, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
}
static LY_ERR
@@ -472,13 +474,14 @@
static LY_ERR
test_parse_lyb_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_LYB, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_LYB, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+ ts_start, ts_end);
}
static LY_ERR
test_parse_lyb_file_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
{
- return _test_parse(state, LYD_LYB, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+ return _test_parse(state, LYD_LYB, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
}
static LY_ERR