lyd_list_equal(struct lyd_node *node1, struct lyd_node *node2, int with_defaults)
{
    int i, diff_ctx;
    struct lyd_node *elem1, *next1, *elem2, *next2;
    struct lys_node *elem1_sch;
    struct ly_ctx *ctx = node2->schema->module->ctx;

    diff_ctx = (node1->schema->module->ctx != node2->schema->module->ctx);

    switch (node2->schema->nodetype) {
    case LYS_LEAFLIST:
        if (lyd_leaf_val_equal(node1, node2, diff_ctx) && (!with_defaults || (node1->dflt == node2->dflt))) {
            return 1;
        }
        break;
    case LYS_LIST:
        if (((struct lys_node_list *)node1->schema)->keys_size) {
            /* lists with keys, their equivalence isb ased on their keys */
            elem1 = node1->child;
            elem2 = node2->child;
            elem1_sch = NULL;
            /* the exact data order is guaranteed */
            for (i = 0; i < ((struct lys_node_list *)node1->schema)->keys_size; ++i) {
                if (diff_ctx && elem1) {
                    /* we have different contexts */
                    if (!elem1_sch) {
                        elem1_sch = lyd_get_schema_inctx(elem1, ctx);
                        if (!elem1_sch) {
                            LOGERR(ctx, LY_EINVAL, "Target context does not contain a required schema node (%s:%s).",
                                   lyd_node_module(elem1)->name, elem1->schema->name);
                            return -1;
                        }
                    } else {
                        /* just move to the next schema node */
                        elem1_sch = elem1_sch->next;
                    }
                }
                if (!elem1 || !elem2 || ((elem1_sch ? elem1_sch : elem1->schema) != elem2->schema)
                        || !lyd_leaf_val_equal(elem1, elem2, diff_ctx)) {
                    break;
                }
                elem1 = elem1->next;
                elem2 = elem2->next;
            }
            if (i == ((struct lys_node_list *)node1->schema)->keys_size) {
                return 1;
            }
        } else {
            /* lists wihtout keys, their equivalence is based on values of all the children (both dierct and indirect) */
            if (!node1->child && !node2->child) {
                /* no children, nothing to compare */
                return 1;
            }

            /* status lists without keys, we need to compare all the children :( */

            /* LY_TREE_DFS_BEGIN for 2 data trees */
            elem1 = next1 = node1->child;
            elem2 = next2 = node2->child;
            while (elem1 && elem2) {
                /* node comparison */
#ifdef LY_ENABLED_CACHE
                if (elem1->hash != elem2->hash) {
                    break;
                }
#endif
                if (diff_ctx) {
                    elem1_sch = lyd_get_schema_inctx(elem1, ctx);
                    if (!elem1_sch) {
                        LOGERR(ctx, LY_EINVAL, "Target context does not contain a required schema node (%s:%s).",
                               lyd_node_module(elem1)->name, elem1->schema->name);
                        return -1;
                    }
                } else {
                    elem1_sch = elem1->schema;
                }
                if (elem1_sch != elem2->schema) {
                    break;
                }
                if (elem2->schema->nodetype == LYS_LIST) {
                    if (!lyd_list_has_keys(elem1) && !lyd_list_has_keys(elem2)) {
                        /* we encountered lists without keys (but have some defined in schema), ignore them for comparison */
                        next1 = NULL;
                        next2 = NULL;
                        goto next_sibling;
                    }
                    /* we will compare all the children of this list instance, not just keys */
                } else if (elem2->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
                    if (!lyd_leaf_val_equal(elem1, elem2, diff_ctx) && (!with_defaults || (elem1->dflt == elem2->dflt))) {
                        break;
                    }
                } else if (elem2->schema->nodetype & LYS_ANYDATA) {
                    if (!lyd_anydata_equal(elem1, elem2)) {
                        break;
                    }
                }

                /* LY_TREE_DFS_END for 2 data trees */
                if (elem2->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
                    next1 = NULL;
                    next2 = NULL;
                } else {
                    next1 = elem1->child;
                    next2 = elem2->child;
                }

next_sibling:
                if (!next1) {
                    next1 = elem1->next;
                }
                if (!next2) {
                    next2 = elem2->next;
                }

                while (!next1) {
                    elem1 = elem1->parent;
                    if (elem1 == node1) {
                        break;
                    }
                    next1 = elem1->next;
                }
                while (!next2) {
                    elem2 = elem2->parent;
                    if (elem2 == node2) {
                        break;
                    }
                    next2 = elem2->next;
                }

                elem1 = next1;
                elem2 = next2;
            }

            if (!elem1 && !elem2) {
                /* all children were successfully compared */
                return 1;
            }
        }
        break;
    default:
        LOGINT(ctx);
        return -1;
    }

    return 0;
}