data tree FEATURE use hashes of data nodes to be able to compare them effectively
diff --git a/src/tree_data.c b/src/tree_data.c
index 19a3549..11371b3 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -535,4 +535,141 @@
}
}
+API LY_ERR
+lyd_compare(const struct lyd_node *node1, const struct lyd_node *node2, int options)
+{
+ const struct lyd_node *iter1, *iter2;
+ struct lyd_node_term *term1, *term2;
+ struct lyd_node_any *any1, *any2;
+ struct lysc_type *type;
+ size_t len1, len2;
+ if (!node1 || !node2) {
+ if (node1 == node2) {
+ return LY_SUCCESS;
+ } else {
+ return LY_ENOT;
+ }
+ }
+
+ if (node1->schema->module->ctx != node2->schema->module->ctx || node1->schema != node2 ->schema) {
+ return LY_ENOT;
+ }
+
+ if (node1->hash != node2->hash) {
+ return LY_ENOT;
+ }
+
+ /* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
+
+ switch (node1->schema->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ if (options & LYD_COMPARE_DEFAULTS) {
+ if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
+ return LY_ENOT;
+ }
+ }
+
+ term1 = (struct lyd_node_term*)node1;
+ term2 = (struct lyd_node_term*)node2;
+ type = ((struct lysc_node_leaf*)node1->schema)->type;
+
+ return type->plugin->compare(&term1->value, &term2->value);
+ case LYS_CONTAINER:
+ if (options & LYD_COMPARE_DEFAULTS) {
+ if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
+ return LY_ENOT;
+ }
+ }
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ iter1 = ((struct lyd_node_inner*)node1)->child;
+ iter2 = ((struct lyd_node_inner*)node2)->child;
+ goto all_children_compare;
+ }
+ return LY_SUCCESS;
+ case LYS_ACTION:
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ /* TODO action/RPC
+ goto all_children_compare;
+ */
+ }
+ return LY_SUCCESS;
+ case LYS_NOTIF:
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ /* TODO Notification
+ goto all_children_compare;
+ */
+ }
+ return LY_SUCCESS;
+ case LYS_LIST:
+ iter1 = ((struct lyd_node_inner*)node1)->child;
+ iter2 = ((struct lyd_node_inner*)node2)->child;
+
+ if (((struct lysc_node_list*)node1->schema)->keys && (!options & LYD_COMPARE_FULL_RECURSION)) {
+ /* lists with keys, their equivalence is based on their keys */
+ unsigned int u;
+
+ LY_ARRAY_FOR(((struct lysc_node_list*)node1->schema)->keys, u) {
+ if (lyd_compare(iter1, iter2, options)) {
+ return LY_ENOT;
+ }
+ iter1 = iter1->next;
+ iter2 = iter2->next;
+ }
+ } else {
+ /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
+
+all_children_compare:
+ if (!iter1 && !iter2) {
+ /* no children, nothing to compare */
+ return LY_SUCCESS;
+ }
+
+ for (; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
+ if (lyd_compare(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION)) {
+ return LY_ENOT;
+ }
+ }
+ if (iter1 || iter2) {
+ return LY_ENOT;
+ }
+ }
+ return LY_SUCCESS;
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ any1 = (struct lyd_node_any*)node1;
+ any2 = (struct lyd_node_any*)node2;
+
+ if (any1->value_type != any2->value_type) {
+ return LY_ENOT;
+ }
+ switch (any1->value_type) {
+ case LYD_ANYDATA_DATATREE:
+ iter1 = any1->value.tree;
+ iter2 = any2->value.tree;
+ goto all_children_compare;
+ case LYD_ANYDATA_STRING:
+ case LYD_ANYDATA_XML:
+ case LYD_ANYDATA_JSON:
+ len1 = strlen(any1->value.str);
+ len2 = strlen(any2->value.str);
+ if (len1 != len2 || strcmp(any1->value.str, any2->value.str)) {
+ return LY_ENOT;
+ }
+ return LY_SUCCESS;
+#if 0 /* TODO LYB format */
+ case LYD_ANYDATA_LYB:
+ int len1 = lyd_lyb_data_length(any1->value.mem);
+ int len2 = lyd_lyb_data_length(any2->value.mem);
+ if (len1 != len2 || memcmp(any1->value.mem, any2->value.mem, len1)) {
+ return LY_ENOT;
+ }
+ return LY_SUCCESS;
+#endif
+ }
+ }
+
+ LOGINT(node1->schema->module->ctx);
+ return LY_EINT;
+}