#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "dict.h"
#include "log.h"
#include "ly_common.h"
#include "metadata.h"
#include "plugins_internal.h"
#include "plugins_types.h"
#include "tree.h"
#include "tree_data.h"
#include "tree_data_internal.h"
#include "tree_data_sorted.h"
#define RB_BLACK 0
#define RB_RED 1
struct rb_node {
struct rb_node *parent;
struct rb_node *left;
struct rb_node *right;
struct lyd_node *dnode;
uint8_t color;
};
#define RBN_LEFT(NODE) ((NODE)->left)
#define RBN_RIGHT(NODE) ((NODE)->right)
#define RBN_PARENT(NODE) ((NODE)->parent)
#define RBN_DNODE(NODE) ((NODE)->dnode)
#define RBN_COLOR(NODE) ((NODE)->color)
#define RBN_COPY(DST, SRC) \
RBN_PARENT(DST) = RBN_PARENT(SRC); \
RBN_LEFT(DST) = RBN_LEFT(SRC); \
RBN_RIGHT(DST) = RBN_RIGHT(SRC); \
RBN_COLOR(DST) = RBN_COLOR(SRC);
#define RBN_RESET(RBN, DNODE) \
*(RBN) = (const struct rb_node){0}; \
RBN_DNODE(RBN) = DNODE;
#define RBT_GET(META, RBT) \
{ \
struct lyd_value_lyds_tree *_lt; \
LYD_VALUE_GET(&META->value, _lt); \
RBT = _lt ? _lt->rbt : NULL; \
}
#define RBT_SET(META, RBT) \
{ \
struct lyd_value_lyds_tree *_lt; \
LYD_VALUE_GET(&META->value, _lt); \
_lt->rbt = RBT; \
}
static struct rb_node *
lyds_get_rb_tree(const struct lyd_node *leader, struct lyd_meta **meta)
{
struct rb_node *rbt;
struct lyd_meta *iter;
if (meta) {
*meta = NULL;
}
LY_LIST_FOR(leader->meta, iter) {
if (!strcmp(iter->name, "lyds_tree")) {
if (meta) {
*meta = iter;
}
RBT_GET(iter, rbt);
return rbt;
}
}
return NULL;
}
static int
rb_sort_clb(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
{
assert(val1->realtype == val2->realtype);
return LYSC_GET_TYPE_PLG(val1->realtype->plugin_ref)->sort(ctx, val1, val2);
}
static int
rb_compare_leaflists(const struct lyd_node *n1, const struct lyd_node *n2)
{
struct lyd_value *val1, *val2;
assert(n2->schema->nodetype == LYS_LEAFLIST);
assert(n1->schema->nodetype == LYS_LEAFLIST);
val1 = &((struct lyd_node_term *)n1)->value;
val2 = &((struct lyd_node_term *)n2)->value;
return rb_sort_clb(LYD_CTX(n1), val1, val2);
}
static int
rb_compare_lists(const struct lyd_node *n1, const struct lyd_node *n2)
{
const struct lyd_node *k1, *k2;
struct lyd_value *val1, *val2;
int cmp;
assert(n1->schema->nodetype & LYS_LIST);
assert(n2->schema->nodetype & LYS_LIST);
k1 = ((const struct lyd_node_inner *)n1)->child;
k2 = ((const struct lyd_node_inner *)n2)->child;
val1 = &((struct lyd_node_term *)k1)->value;
val2 = &((struct lyd_node_term *)k2)->value;
cmp = rb_sort_clb(LYD_CTX(n1), val1, val2);
if (cmp != 0) {
return cmp;
}
k1 = k1->next;
k2 = k2->next;
while (k1 && k1->schema && (k1->schema->flags & LYS_KEY)) {
assert(k1->schema == k2->schema);
val1 = &((struct lyd_node_term *)k1)->value;
val2 = &((struct lyd_node_term *)k2)->value;
cmp = rb_sort_clb(LYD_CTX(n1), val1, val2);
if (cmp != 0) {
return cmp;
}
k1 = k1->next;
k2 = k2->next;
}
return cmp;
}
static void
rb_free_node(struct rb_node **rbn)
{
free(*rbn);
*rbn = NULL;
}
static struct rb_node *
rb_iter_traversal(struct rb_node *current_state, struct rb_node **next_state)
{
struct rb_node *iter, *parent, *next;
for (iter = current_state; iter; iter = next) {
if (RBN_LEFT(iter)) {
next = RBN_LEFT(iter);
continue;
} else if (RBN_RIGHT(iter)) {
next = RBN_RIGHT(iter);
continue;
}
*next_state = parent = RBN_PARENT(iter);
if (parent && (RBN_LEFT(parent) == iter)) {
RBN_LEFT(parent) = NULL;
} else if (parent && (RBN_RIGHT(parent) == iter)) {
RBN_RIGHT(parent) = NULL;
}
return iter;
}
return NULL;
}
static struct rb_node *
rb_iter_begin(struct rb_node *rbt, struct rb_node **iter_state)
{
return rb_iter_traversal(rbt, iter_state);
}
static struct rb_node *
rb_iter_next(struct rb_node **iter_state)
{
return rb_iter_traversal(*iter_state, iter_state);
}
void
lyds_free_tree(struct rb_node *rbt)
{
struct rb_node *rbn, *iter_state;
for (rbn = rb_iter_begin(rbt, &iter_state); rbn; rbn = rb_iter_next(&iter_state)) {
rb_free_node(&rbn);
}
}
static void
rb_set(struct rb_node *rbn, struct rb_node *parent)
{
RBN_PARENT(rbn) = parent;
RBN_LEFT(rbn) = RBN_RIGHT(rbn) = NULL;
RBN_COLOR(rbn) = RB_RED;
}
static void
rb_set_blackred(struct rb_node *black, struct rb_node *red)
{
RBN_COLOR(black) = RB_BLACK;
RBN_COLOR(red) = RB_RED;
}
static void
rb_rotate_left(struct rb_node **rbt, struct rb_node *rbn)
{
struct rb_node *parent;
struct rb_node *tmp;
tmp = RBN_RIGHT(rbn);
RBN_RIGHT(rbn) = RBN_LEFT(tmp);
if (RBN_RIGHT(rbn) != NULL) {
RBN_PARENT(RBN_LEFT(tmp)) = rbn;
}
parent = RBN_PARENT(rbn);
RBN_PARENT(tmp) = parent;
if (parent != NULL) {
if (rbn == RBN_LEFT(parent)) {
RBN_LEFT(parent) = tmp;
} else {
RBN_RIGHT(parent) = tmp;
}
} else {
*rbt = tmp;
}
RBN_LEFT(tmp) = rbn;
RBN_PARENT(rbn) = tmp;
}
static void
rb_rotate_right(struct rb_node **rbt, struct rb_node *rbn)
{
struct rb_node *parent;
struct rb_node *tmp;
tmp = RBN_LEFT(rbn);
RBN_LEFT(rbn) = RBN_RIGHT(tmp);
if (RBN_LEFT(rbn) != NULL) {
RBN_PARENT(RBN_RIGHT(tmp)) = rbn;
}
parent = RBN_PARENT(rbn);
RBN_PARENT(tmp) = parent;
if (parent != NULL) {
if (rbn == RBN_LEFT(parent)) {
RBN_LEFT(parent) = tmp;
} else {
RBN_RIGHT(parent) = tmp;
}
} else {
*rbt = tmp;
}
RBN_RIGHT(tmp) = rbn;
RBN_PARENT(rbn) = tmp;
}
static void
rb_insert_color(struct rb_node **rbt, struct rb_node *rbn)
{
struct rb_node *parent, *gparent, *tmp;
while ((parent = RBN_PARENT(rbn)) != NULL &&
RBN_COLOR(parent) == RB_RED) {
gparent = RBN_PARENT(parent);
if (parent == RBN_LEFT(gparent)) {
tmp = RBN_RIGHT(gparent);
if ((tmp != NULL) && (RBN_COLOR(tmp) == RB_RED)) {
RBN_COLOR(tmp) = RB_BLACK;
rb_set_blackred(parent, gparent);
rbn = gparent;
continue;
}
if (RBN_RIGHT(parent) == rbn) {
rb_rotate_left(rbt, parent);
tmp = parent;
parent = rbn;
rbn = tmp;
}
rb_set_blackred(parent, gparent);
rb_rotate_right(rbt, gparent);
} else {
tmp = RBN_LEFT(gparent);
if ((tmp != NULL) && (RBN_COLOR(tmp) == RB_RED)) {
RBN_COLOR(tmp) = RB_BLACK;
rb_set_blackred(parent, gparent);
rbn = gparent;
continue;
}
if (RBN_LEFT(parent) == rbn) {
rb_rotate_right(rbt, parent);
tmp = parent;
parent = rbn;
rbn = tmp;
}
rb_set_blackred(parent, gparent);
rb_rotate_left(rbt, gparent);
}
}
RBN_COLOR(*rbt) = RB_BLACK;
}
static void
rb_remove_color(struct rb_node **rbt, struct rb_node *parent, struct rb_node *rbn)
{
struct rb_node *tmp;
while ((rbn == NULL || RBN_COLOR(rbn) == RB_BLACK) &&
rbn != *rbt && parent) {
if (RBN_LEFT(parent) == rbn) {
tmp = RBN_RIGHT(parent);
if (RBN_COLOR(tmp) == RB_RED) {
rb_set_blackred(tmp, parent);
rb_rotate_left(rbt, parent);
tmp = RBN_RIGHT(parent);
}
if (((RBN_LEFT(tmp) == NULL) ||
(RBN_COLOR(RBN_LEFT(tmp)) == RB_BLACK)) &&
((RBN_RIGHT(tmp) == NULL) ||
(RBN_COLOR(RBN_RIGHT(tmp)) == RB_BLACK))) {
RBN_COLOR(tmp) = RB_RED;
rbn = parent;
parent = RBN_PARENT(rbn);
} else {
if ((RBN_RIGHT(tmp) == NULL) ||
(RBN_COLOR(RBN_RIGHT(tmp)) == RB_BLACK)) {
struct rb_node *oleft;
oleft = RBN_LEFT(tmp);
if (oleft != NULL) {
RBN_COLOR(oleft) = RB_BLACK;
}
RBN_COLOR(tmp) = RB_RED;
rb_rotate_right(rbt, tmp);
tmp = RBN_RIGHT(parent);
}
RBN_COLOR(tmp) = RBN_COLOR(parent);
RBN_COLOR(parent) = RB_BLACK;
if (RBN_RIGHT(tmp)) {
RBN_COLOR(RBN_RIGHT(tmp)) = RB_BLACK;
}
rb_rotate_left(rbt, parent);
rbn = *rbt;
break;
}
} else {
tmp = RBN_LEFT(parent);
if (RBN_COLOR(tmp) == RB_RED) {
rb_set_blackred(tmp, parent);
rb_rotate_right(rbt, parent);
tmp = RBN_LEFT(parent);
}
if (((RBN_LEFT(tmp) == NULL) ||
(RBN_COLOR(RBN_LEFT(tmp)) == RB_BLACK)) &&
((RBN_RIGHT(tmp) == NULL) ||
(RBN_COLOR(RBN_RIGHT(tmp)) == RB_BLACK))) {
RBN_COLOR(tmp) = RB_RED;
rbn = parent;
parent = RBN_PARENT(rbn);
} else {
if ((RBN_LEFT(tmp) == NULL) ||
(RBN_COLOR(RBN_LEFT(tmp)) == RB_BLACK)) {
struct rb_node *oright;
oright = RBN_RIGHT(tmp);
if (oright != NULL) {
RBN_COLOR(oright) = RB_BLACK;
}
RBN_COLOR(tmp) = RB_RED;
rb_rotate_left(rbt, tmp);
tmp = RBN_LEFT(parent);
}
RBN_COLOR(tmp) = RBN_COLOR(parent);
RBN_COLOR(parent) = RB_BLACK;
if (RBN_LEFT(tmp) != NULL) {
RBN_COLOR(RBN_LEFT(tmp)) = RB_BLACK;
}
rb_rotate_right(rbt, parent);
rbn = *rbt;
break;
}
}
}
if (rbn != NULL) {
RBN_COLOR(rbn) = RB_BLACK;
}
}
static struct rb_node *
rb_remove(struct rb_node **rbt, struct rb_node *rbn)
{
struct rb_node *child, *parent, *old = rbn;
uint8_t color;
if (RBN_LEFT(rbn) == NULL) {
child = RBN_RIGHT(rbn);
} else if (RBN_RIGHT(rbn) == NULL) {
child = RBN_LEFT(rbn);
} else {
struct rb_node *tmp;
rbn = RBN_RIGHT(rbn);
while ((tmp = RBN_LEFT(rbn)) != NULL) {
rbn = tmp;
}
child = RBN_RIGHT(rbn);
parent = RBN_PARENT(rbn);
color = RBN_COLOR(rbn);
if (child != NULL) {
RBN_PARENT(child) = parent;
}
if (parent != NULL) {
if (RBN_LEFT(parent) == rbn) {
RBN_LEFT(parent) = child;
} else {
RBN_RIGHT(parent) = child;
}
} else {
*rbt = child;
}
if (RBN_PARENT(rbn) == old) {
parent = rbn;
}
RBN_COPY(rbn, old);
tmp = RBN_PARENT(old);
if (tmp != NULL) {
if (RBN_LEFT(tmp) == old) {
RBN_LEFT(tmp) = rbn;
} else {
RBN_RIGHT(tmp) = rbn;
}
} else {
*rbt = rbn;
}
RBN_PARENT(RBN_LEFT(old)) = rbn;
if (RBN_RIGHT(old)) {
RBN_PARENT(RBN_RIGHT(old)) = rbn;
}
goto color;
}
parent = RBN_PARENT(rbn);
color = RBN_COLOR(rbn);
if (child != NULL) {
RBN_PARENT(child) = parent;
}
if (parent != NULL) {
if (RBN_LEFT(parent) == rbn) {
RBN_LEFT(parent) = child;
} else {
RBN_RIGHT(parent) = child;
}
} else {
*rbt = child;
}
color:
if (color == RB_BLACK) {
rb_remove_color(rbt, parent, child);
}
return old;
}
static void
rb_insert_node(struct rb_node **rbt, struct rb_node *rbn, ly_bool *max_p)
{
ly_bool max;
struct rb_node *tmp;
struct rb_node *parent = NULL;
int comp = 0;
int (*rb_compare)(const struct lyd_node *n1, const struct lyd_node *n2);
if (RBN_DNODE(*rbt)->schema->nodetype == LYS_LEAFLIST) {
rb_compare = rb_compare_leaflists;
} else {
rb_compare = rb_compare_lists;
}
max = 1;
tmp = *rbt;
while (tmp != NULL) {
parent = tmp;
comp = rb_compare(RBN_DNODE(tmp), RBN_DNODE(rbn));
if (comp > 0) {
tmp = RBN_LEFT(tmp);
max = 0;
} else {
tmp = RBN_RIGHT(tmp);
}
}
rb_set(rbn, parent);
if (parent != NULL) {
if (comp > 0) {
RBN_LEFT(parent) = rbn;
} else {
RBN_RIGHT(parent) = rbn;
}
} else {
*rbt = rbn;
}
rb_insert_color(rbt, rbn);
if (max_p) {
*max_p = max;
}
}
static struct rb_node *
rb_prev(struct rb_node *rbn)
{
if (RBN_LEFT(rbn)) {
rbn = RBN_LEFT(rbn);
while (RBN_RIGHT(rbn)) {
rbn = RBN_RIGHT(rbn);
}
} else {
if (RBN_PARENT(rbn) && (rbn == RBN_RIGHT(RBN_PARENT(rbn)))) {
rbn = RBN_PARENT(rbn);
} else {
while (RBN_PARENT(rbn) &&
(rbn == RBN_LEFT(RBN_PARENT(rbn)))) {
rbn = RBN_PARENT(rbn);
}
rbn = RBN_PARENT(rbn);
}
}
return rbn;
}
static struct rb_node *
rb_next(struct rb_node *rbn)
{
if (RBN_RIGHT(rbn) != NULL) {
rbn = RBN_RIGHT(rbn);
while (RBN_LEFT(rbn) != NULL) {
rbn = RBN_LEFT(rbn);
}
} else {
if (RBN_PARENT(rbn) && (rbn == RBN_LEFT(RBN_PARENT(rbn)))) {
rbn = RBN_PARENT(rbn);
} else {
while (RBN_PARENT(rbn) &&
(rbn == RBN_RIGHT(RBN_PARENT(rbn)))) {
rbn = RBN_PARENT(rbn);
}
rbn = RBN_PARENT(rbn);
}
}
return rbn;
}
static struct rb_node *
rb_find(struct rb_node *rbt, struct lyd_node *target)
{
struct rb_node *iter, *pivot;
int comp;
int (*rb_compare)(const struct lyd_node *n1, const struct lyd_node *n2);
if (RBN_DNODE(rbt) == target) {
return rbt;
}
if (RBN_DNODE(rbt)->schema->nodetype == LYS_LEAFLIST) {
rb_compare = rb_compare_leaflists;
} else {
rb_compare = rb_compare_lists;
}
iter = rbt;
do {
comp = rb_compare(RBN_DNODE(iter), target);
if (comp > 0) {
iter = RBN_LEFT(iter);
} else if (comp < 0) {
iter = RBN_RIGHT(iter);
} else if (RBN_DNODE(iter) == target) {
return iter;
} else {
pivot = iter;
for (iter = rb_prev(pivot); iter; iter = rb_prev(iter)) {
if (rb_compare(RBN_DNODE(iter), target) != 0) {
break;
} else if (RBN_DNODE(iter) == target) {
return iter;
}
}
for (iter = rb_next(pivot); iter; iter = rb_next(iter)) {
if (rb_compare(RBN_DNODE(iter), target) != 0) {
break;
} else if (RBN_DNODE(iter) == target) {
return iter;
}
}
break;
}
} while (iter != NULL);
return NULL;
}
LY_ERR
lyds_create_node(struct lyd_node *node, struct rb_node **rbn)
{
*rbn = calloc(1, sizeof **rbn);
LY_CHECK_ERR_RET(!(*rbn), LOGERR(LYD_CTX(node), LY_EMEM, "Allocation of red-black node failed."), LY_EMEM);
RBN_DNODE(*rbn) = node;
return LY_SUCCESS;
}
void
lyds_pool_add(struct lyd_node *leader, struct lyds_pool *pool)
{
struct rb_node *rbt;
struct lyd_meta *root_meta, *tmp;
assert(pool && leader);
rbt = lyds_get_rb_tree(leader, &root_meta);
if (root_meta) {
lyd_unlink_meta_single(root_meta);
if (pool->meta) {
tmp = pool->meta;
pool->meta = root_meta;
root_meta->next = tmp;
} else {
pool->meta = root_meta;
}
}
if (!rbt) {
return;
}
if (pool->rbn) {
RBN_RESET(pool->rbn, NULL);
}
if (pool->iter_state) {
assert(pool->rbn);
if (RBN_LEFT(pool->iter_state)) {
assert(!RBN_RIGHT(pool->iter_state));
RBN_RIGHT(pool->iter_state) = pool->rbn;
} else {
assert(!RBN_LEFT(pool->iter_state));
RBN_LEFT(pool->iter_state) = pool->rbn;
}
RBN_PARENT(pool->rbn) = pool->iter_state;
}
if (pool->rbn) {
RBN_LEFT(pool->rbn) = rbt;
RBN_PARENT(rbt) = pool->rbn;
pool->rbn = rb_iter_begin(rbt, &pool->iter_state);
} else {
pool->rbn = rb_iter_begin(rbt, &pool->iter_state);
}
}
static struct lyd_meta *
lyds_pool_get_meta(struct lyds_pool *pool)
{
struct lyd_meta *meta, *next;
if (!pool->meta) {
return NULL;
}
next = pool->meta->next;
meta = pool->meta;
meta->next = NULL;
pool->meta = next;
return meta;
}
void
lyds_pool_clean(struct lyds_pool *pool)
{
struct lyd_meta *meta, *next;
struct rb_node *iter;
for (iter = pool->rbn; iter; iter = rb_iter_next(&pool->iter_state)) {
rb_free_node(&iter);
}
pool->rbn = NULL;
for (meta = pool->meta; meta; meta = next) {
next = meta->next;
RBT_SET(meta, NULL);
lyd_free_meta_single(meta);
}
pool->meta = NULL;
}
static void
rb_remove_node(struct lyd_meta *root_meta, struct rb_node **rbt, struct lyd_node *node, struct rb_node **removed)
{
struct rb_node *rbn;
assert(root_meta && rbt && node);
if (!*rbt) {
return;
}
rbn = rb_find(*rbt, node);
if (!rbn) {
return;
}
assert(RBN_DNODE(rbn) == node);
rbn = rb_remove(rbt, rbn);
*removed = rbn;
if (rbn == *rbt) {
*rbt = NULL;
}
RBT_SET(root_meta, *rbt);
}
ly_bool
lyds_is_supported(const struct lyd_node *node)
{
if (!node->schema || !(node->schema->flags & LYS_ORDBY_SYSTEM)) {
return 0;
} else if (node->schema->nodetype == LYS_LEAFLIST) {
return 1;
} else if ((node->schema->nodetype == LYS_LIST) && !(node->schema->flags & LYS_KEYLESS)) {
return 1;
} else {
return 0;
}
}
static void
lyds_move_meta(struct lyd_node *dst, struct lyd_meta *meta)
{
lyd_unlink_meta_single(meta);
lyd_insert_meta(dst, meta, 0);
}
static void
lyds_link_data_node(struct lyd_node **first_sibling, struct lyd_node **leader, struct lyd_node *node,
struct lyd_meta *root_meta, struct rb_node *rbn)
{
struct rb_node *prev;
prev = rb_prev(rbn);
if (prev) {
lyd_insert_after_node(first_sibling, RBN_DNODE(prev), RBN_DNODE(rbn));
} else {
lyd_insert_before_node(*leader, RBN_DNODE(rbn));
*leader = node;
lyds_move_meta(node, root_meta);
*first_sibling = node->prev->next ? *first_sibling : node;
}
}
static LY_ERR
lyds_additionally_create_rb_nodes(struct lyd_node **first_sibling, struct lyd_node **leader,
struct lyd_meta *root_meta, struct rb_node **rbt, struct lyd_node *node)
{
LY_ERR ret;
ly_bool max;
struct rb_node *rbn;
struct lyd_node *iter, *next;
for (iter = node; iter && (iter->schema == (*leader)->schema); iter = next) {
next = iter->next;
ret = lyds_create_node(iter, &rbn);
LY_CHECK_RET(ret);
rb_insert_node(rbt, rbn, &max);
if (!max) {
lyd_unlink_ignore_lyds(first_sibling, iter);
lyds_link_data_node(first_sibling, leader, iter, root_meta, rbn);
lyd_insert_hash(iter);
}
}
return LY_SUCCESS;
}
static LY_ERR
lyds_additionally_create_rb_tree(struct lyd_node **first_sibling, struct lyd_node **leader,
struct lyd_meta *root_meta, struct rb_node **rbt)
{
LY_ERR ret;
struct rb_node *rbn;
ret = lyds_create_node(*leader, &rbn);
LY_CHECK_RET(ret);
*rbt = rbn;
ret = lyds_additionally_create_rb_nodes(first_sibling, leader, root_meta, rbt, (*leader)->next);
RBT_SET(root_meta, *rbt);
return ret;
}
static void
lyds_additionally_reuse_rb_tree(struct lyd_node **first_sibling, struct lyd_node **leader, struct lyd_meta *root_meta,
struct rb_node **rbt, struct lyds_pool *pool, struct lyd_node **next)
{
ly_bool max;
struct lyd_node *iter, *next_node;
RBN_RESET(pool->rbn, *leader);
*rbt = pool->rbn;
pool->rbn = rb_iter_next(&pool->iter_state);
for (iter = (*leader)->next; iter && (iter->schema == (*leader)->schema); iter = next_node) {
next_node = iter->next;
if (!pool->rbn) {
*next = iter;
return;
}
RBN_RESET(pool->rbn, iter);
rb_insert_node(rbt, pool->rbn, &max);
if (!max) {
lyd_unlink_ignore_lyds(first_sibling, iter);
lyds_link_data_node(first_sibling, leader, iter, root_meta, pool->rbn);
lyd_insert_hash(iter);
}
pool->rbn = rb_iter_next(&pool->iter_state);
}
*next = NULL;
}
LY_ERR
lyds_create_metadata(struct lyd_node *leader, struct lyd_meta **meta_p)
{
LY_ERR ret;
uint32_t i;
struct lyd_meta *meta;
struct lys_module *modyang;
assert(leader && (!leader->prev->next || (leader->schema != leader->prev->schema)));
lyds_get_rb_tree(leader, &meta);
if (meta) {
return LY_SUCCESS;
}
i = 0;
while ((modyang = ly_ctx_get_module_iter(LYD_CTX(leader), &i))) {
if (!strcmp(modyang->name, "yang")) {
break;
}
}
LY_CHECK_ERR_RET(!modyang, LOGERR(LYD_CTX(leader), LY_EINT, "The yang module is not installed."), LY_EINT);
ret = lyd_create_meta(leader, &meta, modyang, "lyds_tree", 9, NULL, 0, 0, 1, NULL, LY_VALUE_CANON, NULL,
LYD_HINT_DATA, NULL, NULL, 0, NULL);
LY_CHECK_RET(ret);
if (meta_p) {
*meta_p = meta;
}
return LY_SUCCESS;
}
static LY_ERR
rb_insert(struct lyd_node *node, struct rb_node **rbt, struct rb_node **rbn)
{
LY_ERR ret;
ret = lyds_create_node(node, rbn);
LY_CHECK_RET(ret);
rb_insert_node(rbt, *rbn, NULL);
return LY_SUCCESS;
}
LY_ERR
lyds_insert(struct lyd_node **first_sibling, struct lyd_node **leader, struct lyd_node *node)
{
LY_ERR ret;
struct rb_node *rbt, *rbn;
struct lyd_meta *root_meta;
assert(LYD_NODE_IS_ALONE(node) && leader && node);
rbt = lyds_get_rb_tree(node, &root_meta);
if (root_meta) {
assert(!rbt || (!RBN_LEFT(rbt) && !RBN_RIGHT(rbt)));
lyd_free_meta_single(root_meta);
}
rbt = lyds_get_rb_tree(*leader, &root_meta);
if (!root_meta) {
LY_CHECK_RET(lyds_create_metadata(*leader, &root_meta));
}
if (!rbt) {
ret = lyds_additionally_create_rb_tree(first_sibling, leader, root_meta, &rbt);
LY_CHECK_RET(ret);
}
ret = rb_insert(node, &rbt, &rbn);
LY_CHECK_RET(ret);
lyds_link_data_node(first_sibling, leader, node, root_meta, rbn);
RBT_SET(root_meta, rbt);
return LY_SUCCESS;
}
LY_ERR
lyds_insert2(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node **leader,
struct lyd_node *node, struct lyds_pool *pool)
{
LY_ERR ret;
struct rb_node *rbt = NULL, *rbn;
struct lyd_node *ld, *next;
struct lyd_meta *root_meta;
assert(pool && pool->rbn && first_sibling && node);
if (!*leader || ((*leader)->schema != node->schema)) {
ld = NULL;
lyd_find_sibling_schema(*first_sibling, node->schema, &ld);
if (!ld) {
lyd_insert_node_ordby_schema(parent, first_sibling, node);
*leader = node;
goto cleanup;
} else {
*leader = ld;
}
}
rbt = lyds_get_rb_tree(*leader, &root_meta);
if (!root_meta) {
root_meta = lyds_pool_get_meta(pool);
if (!root_meta) {
ret = lyds_create_metadata(*leader, &root_meta);
LY_CHECK_RET(ret);
} else {
lyd_insert_meta(*leader, root_meta, 0);
}
}
if (!rbt) {
lyds_additionally_reuse_rb_tree(first_sibling, leader, root_meta, &rbt, pool, &next);
if (next) {
ret = lyds_additionally_create_rb_nodes(first_sibling, leader, root_meta, &rbt, next);
LY_CHECK_RET(ret);
}
}
if (pool->rbn) {
rbn = pool->rbn;
RBN_RESET(rbn, node);
rb_insert_node(&rbt, rbn, NULL);
pool->rbn = rb_iter_next(&pool->iter_state);
} else {
ret = rb_insert(node, &rbt, &rbn);
LY_CHECK_RET(ret);
}
lyds_link_data_node(first_sibling, leader, node, root_meta, rbn);
cleanup:
if (rbt) {
RBT_SET(root_meta, rbt);
}
lyd_insert_hash(node);
*first_sibling = node->prev->next ? *first_sibling : node;
return LY_SUCCESS;
}
void
lyds_unlink(struct lyd_node **leader, struct lyd_node *node)
{
struct rb_node *rbt, *removed = NULL;
struct lyd_meta *root_meta;
if (!node || !leader || !*leader) {
return;
}
rbt = lyds_get_rb_tree(*leader, &root_meta);
if (!root_meta || LYD_NODE_IS_ALONE(*leader)) {
return;
}
if (*leader == node) {
lyds_move_meta((*leader)->next, root_meta);
}
rb_remove_node(root_meta, &rbt, node, &removed);
rb_free_node(&removed);
}
void
lyds_split(struct lyd_node **first_sibling, struct lyd_node *leader, struct lyd_node *node, struct lyd_node **next_p)
{
struct rb_node *rbt, *rbn;
struct lyd_node *iter, *next, *start, *dst;
struct lyd_meta *root_meta;
assert(leader && node);
rbt = lyds_get_rb_tree(leader, &root_meta);
if (!rbt || (leader == node)) {
start = node->next;
lyd_unlink_ignore_lyds(first_sibling, node);
dst = node;
LY_LIST_FOR_SAFE(start, next, iter) {
if (iter->schema != node->schema) {
break;
}
lyd_unlink_ignore_lyds(first_sibling, iter);
lyd_insert_after_node(&node, dst, iter);
dst = iter;
}
*next_p = iter;
return;
}
start = node->next;
if (!start || (start->schema != node->schema)) {
rb_remove_node(root_meta, &rbt, node, &rbn);
rb_free_node(&rbn);
lyd_unlink_ignore_lyds(first_sibling, node);
*next_p = start;
goto cleanup;
}
rb_remove_node(root_meta, &rbt, node, &rbn);
rb_free_node(&rbn);
lyd_unlink_ignore_lyds(first_sibling, node);
dst = node;
LY_LIST_FOR_SAFE(start, next, iter) {
if (iter->schema != node->schema) {
break;
}
rb_remove_node(root_meta, &rbt, iter, &rbn);
rb_free_node(&rbn);
lyd_unlink_ignore_lyds(first_sibling, iter);
lyd_insert_after_node(&node, dst, iter);
dst = iter;
}
*next_p = iter;
cleanup:
RBT_SET(root_meta, rbt);
}
void
lyds_free_metadata(struct lyd_node *node)
{
struct lyd_meta *root_meta;
if (node) {
lyds_get_rb_tree(node, &root_meta);
lyd_free_meta_single(root_meta);
}
}
static LY_ERR
lyds_merge_nodes1(struct lyd_node **first_dst, struct lyd_node **leader_dst, struct lyd_meta *root_meta_dst,
struct rb_node *rbt_dst, struct lyd_node **first_src, struct lyd_node *leader_src, struct lyd_node **next_p)
{
LY_ERR ret;
struct rb_node *rbn;
struct lyd_node *iter, *next;
const struct lysc_node *schema;
schema = leader_src->schema;
for (iter = leader_src; iter && (iter->schema == schema); iter = next) {
ret = rb_insert(iter, &rbt_dst, &rbn);
if (ret) {
break;
}
next = iter->next;
lyd_unlink_ignore_lyds(first_src, iter);
lyds_link_data_node(first_dst, leader_dst, iter, root_meta_dst, rbn);
lyd_insert_hash(iter);
}
*next_p = iter;
RBT_SET(root_meta_dst, rbt_dst);
return LY_SUCCESS;
}
static LY_ERR
lyds_merge_nodes2_front(struct lyd_node **leader_dst, struct lyd_node **first_src, struct lyd_node *leader_src,
struct rb_node **rbt_src, struct rb_node **dst_iter, struct lyd_node **next_p)
{
LY_ERR ret;
struct rb_node *prev, *iter;
struct lyd_node *dst;
ret = rb_insert(*leader_dst, rbt_src, dst_iter);
LY_CHECK_ERR_RET(ret, *next_p = leader_src, ret);
prev = rb_prev(*dst_iter);
dst = *leader_dst;
for (iter = prev; iter; iter = rb_prev(iter)) {
lyd_unlink_ignore_lyds(first_src, RBN_DNODE(iter));
lyd_insert_before_node(dst, RBN_DNODE(iter));
lyd_insert_hash(RBN_DNODE(iter));
dst = RBN_DNODE(iter);
}
if (prev) {
*leader_dst = dst;
}
return LY_SUCCESS;
}
static LY_ERR
lyds_merge_nodes2_among(struct lyd_node **first_dst, struct lyd_node **leader_dst, struct lyd_node **first_src,
struct rb_node **rbt_src, struct rb_node **dst_iter, struct lyd_node **next_p)
{
LY_ERR ret;
struct rb_node *rbn, *iter, *rbn_prev;
struct lyd_node *dst, *node;
const struct lysc_node *schema;
schema = (*leader_dst)->schema;
rbn = *dst_iter;
for (node = RBN_DNODE(*dst_iter); node->next && (node->schema == schema); node = dst->next) {
rbn_prev = rbn;
ret = rb_insert(node->next, rbt_src, &rbn);
LY_CHECK_ERR_RET(ret, *next_p = RBN_DNODE(rb_next(rbn_prev)), ret);
dst = node;
for (iter = rb_next(rbn_prev); iter != rbn; iter = rb_next(iter)) {
lyd_unlink_ignore_lyds(first_src, RBN_DNODE(iter));
lyd_insert_after_node(first_dst, dst, RBN_DNODE(iter));
lyd_insert_hash(RBN_DNODE(iter));
dst = RBN_DNODE(iter);
}
}
*dst_iter = rbn;
return LY_SUCCESS;
}
static void
lyds_merge_nodes2_back(struct lyd_node **first_dst, struct lyd_node **first_src, struct rb_node *dst_iter,
struct lyd_node **next_p)
{
struct rb_node *iter, *begin;
struct lyd_node *dst;
begin = rb_next(dst_iter);
LY_CHECK_RET(!begin,; );
dst = RBN_DNODE(dst_iter);
for (iter = begin; iter; iter = rb_next(iter)) {
*next_p = RBN_DNODE(iter)->next;
lyd_unlink_ignore_lyds(first_src, RBN_DNODE(iter));
lyd_insert_after_node(first_dst, dst, RBN_DNODE(iter));
lyd_insert_hash(RBN_DNODE(iter));
dst = RBN_DNODE(iter);
}
}
static LY_ERR
lyds_merge_nodes2(struct lyd_node **first_dst, struct lyd_node **leader_dst,
struct lyd_node **first_src, struct lyd_node *leader_src, struct lyd_meta *root_meta_src,
struct rb_node *rbt_src, struct lyd_node **next_p)
{
LY_ERR ret;
struct rb_node *dst_iter;
ret = lyds_merge_nodes2_front(leader_dst, first_src, leader_src, &rbt_src, &dst_iter, next_p);
LY_CHECK_GOTO(ret, cleanup);
*first_dst = !(*first_dst)->prev->next ? *first_dst : *leader_dst;
lyds_move_meta(*leader_dst, root_meta_src);
ret = lyds_merge_nodes2_among(first_dst, leader_dst, first_src, &rbt_src, &dst_iter, next_p);
LY_CHECK_GOTO(ret, cleanup);
lyds_merge_nodes2_back(first_dst, first_src, dst_iter, next_p);
if (*next_p && ((*next_p)->schema == (*leader_dst)->schema)) {
ret = lyds_merge_nodes1(first_dst, leader_dst, root_meta_src, rbt_src, first_src, *next_p, next_p);
}
cleanup:
RBT_SET(root_meta_src, rbt_src);
return ret;
}
static LY_ERR
lyds_merge_nodes3(struct lyd_node **first_dst, struct lyd_node **leader_dst, struct lyd_meta *root_meta_dst,
struct rb_node *rbt_dst, struct lyd_node **first_src, struct lyd_meta *root_meta_src,
struct rb_node *rbt_src, struct lyd_node **next_p)
{
struct rb_node *iter, *iter_state;
struct lyd_node *node;
RBT_SET(root_meta_src, NULL);
lyd_free_meta_single(root_meta_src);
for (iter = rb_iter_begin(rbt_src, &iter_state); iter; iter = rb_iter_next(&iter_state)) {
node = RBN_DNODE(iter);
*next_p = node->next;
RBN_RESET(iter, node);
rb_insert_node(&rbt_dst, iter, NULL);
lyd_unlink_ignore_lyds(first_src, node);
lyds_link_data_node(first_dst, leader_dst, node, root_meta_dst, iter);
lyd_insert_hash(node);
}
if (!*next_p || ((*next_p)->schema != (*leader_dst)->schema)) {
RBT_SET(root_meta_dst, rbt_dst);
} else {
LY_CHECK_RET(lyds_merge_nodes1(first_dst, leader_dst, root_meta_dst, rbt_dst, first_src, *next_p, next_p));
}
return LY_SUCCESS;
}
LY_ERR
lyds_merge(struct lyd_node **first_dst, struct lyd_node **leader_dst, struct lyd_node **first_src,
struct lyd_node *leader_src, struct lyd_node **next_p)
{
LY_ERR ret = LY_SUCCESS;
struct rb_node *rbt_dst, *rbt_src;
struct lyd_meta *root_meta_dst, *root_meta_src = NULL;
assert(leader_dst && leader_src && next_p);
rbt_dst = lyds_get_rb_tree(*leader_dst, &root_meta_dst);
rbt_src = lyds_get_rb_tree(leader_src, &root_meta_src);
if (root_meta_src && !rbt_src) {
lyd_free_meta_single(root_meta_src);
}
if (!rbt_dst && !rbt_src) {
LY_CHECK_RET(lyds_create_metadata(*leader_dst, &root_meta_dst));
LY_CHECK_RET(lyds_additionally_create_rb_tree(first_dst, leader_dst, root_meta_dst, &rbt_dst));
ret = lyds_merge_nodes1(first_dst, leader_dst, root_meta_dst, rbt_dst, first_src, leader_src, next_p);
} else if (rbt_dst && !rbt_src) {
ret = lyds_merge_nodes1(first_dst, leader_dst, root_meta_dst, rbt_dst, first_src, leader_src, next_p);
} else if (!rbt_dst && rbt_src) {
ret = lyds_merge_nodes2(first_dst, leader_dst, first_src, leader_src, root_meta_src, rbt_src, next_p);
} else {
assert(rbt_dst && rbt_src);
lyds_merge_nodes3(first_dst, leader_dst, root_meta_dst, rbt_dst, first_src, root_meta_src, rbt_src, next_p);
}
return ret;
}
int
lyds_compare_single(struct lyd_node *node1, struct lyd_node *node2)
{
assert(node1 && node2 && (node1->schema == node2->schema) && lyds_is_supported(node1));
if (node1 == node2) {
return 0;
} else if (node1->schema->nodetype == LYS_LEAFLIST) {
return rb_compare_leaflists(node1, node2);
} else {
return rb_compare_lists(node1, node2);
}
}