#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "hash_table.h"
#include "log.h"
#include "ly_common.h"
#include "plugins_internal.h"
#include "plugins_types.h"
#include "tree.h"
#include "tree_data.h"
#include "tree_data_internal.h"
#include "tree_schema.h"
LY_ERR
lyd_hash(struct lyd_node *node)
{
struct lyd_node *iter;
const void *hash_key;
ly_bool dyn;
uint64_t key_size_bits;
if (!node->schema) {
return LY_SUCCESS;
}
node->hash = lyht_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
node->hash = lyht_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
if (node->schema->nodetype == LYS_LIST) {
if (node->schema->flags & LYS_KEYLESS) {
node->hash = lyht_hash_multi(node->hash, NULL, 0);
} else {
struct lyd_node_inner *list = (struct lyd_node_inner *)node;
for (iter = list->child; iter && iter->schema && (iter->schema->flags & LYS_KEY); iter = iter->next) {
struct lyd_node_term *key = (struct lyd_node_term *)iter;
hash_key = LYSC_GET_TYPE_PLG(key->value.realtype->plugin_ref)->print(NULL, &key->value,
LY_VALUE_LYB, NULL, &dyn, &key_size_bits);
node->hash = lyht_hash_multi(node->hash, hash_key, LYPLG_BITS2BYTES(key_size_bits));
if (dyn) {
free((void *)hash_key);
}
}
}
} else if (node->schema->nodetype == LYS_LEAFLIST) {
struct lyd_node_term *llist = (struct lyd_node_term *)node;
hash_key = LYSC_GET_TYPE_PLG(llist->value.realtype->plugin_ref)->print(NULL, &llist->value,
LY_VALUE_LYB, NULL, &dyn, &key_size_bits);
node->hash = lyht_hash_multi(node->hash, hash_key, LYPLG_BITS2BYTES(key_size_bits));
if (dyn) {
free((void *)hash_key);
}
}
node->hash = lyht_hash_multi(node->hash, NULL, 0);
return LY_SUCCESS;
}
ly_bool
lyd_hash_table_val_equal(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
{
struct lyd_node *val1, *val2;
val1 = *((struct lyd_node **)val1_p);
val2 = *((struct lyd_node **)val2_p);
if (mod) {
if (val1 == val2) {
return 1;
} else {
return 0;
}
}
if (val1->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
if (!lyd_compare_single(val1, val2, 0)) {
return 1;
}
} else if (lyd_compare_schema_equal(val1->schema, val2->schema, 1)) {
return 1;
}
return 0;
}
static LY_ERR
lyd_insert_hash_add(struct ly_ht *ht, struct lyd_node *node, ly_bool empty_ht)
{
uint32_t hash;
assert(ht && node && node->schema);
if (lyht_insert_no_check(ht, &node, node->hash, NULL)) {
LOGINT_RET(LYD_CTX(node));
}
if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) &&
(!node->prev->next || (node->prev->schema != node->schema))) {
hash = lyht_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
hash = lyht_hash_multi(hash, node->schema->name, strlen(node->schema->name));
hash = lyht_hash_multi(hash, NULL, 0);
if (!empty_ht && node->next && (node->next->schema == node->schema)) {
if (lyht_remove(ht, &node->next, hash)) {
LOGINT_RET(LYD_CTX(node));
}
}
assert(hash != node->hash);
if (lyht_insert(ht, &node, hash, NULL)) {
LOGINT_RET(LYD_CTX(node));
}
}
return LY_SUCCESS;
}
LY_ERR
lyd_insert_hash(struct lyd_node *node)
{
struct lyd_node *iter;
struct lyd_node_inner *parent;
uint32_t u;
if (!node->parent || !node->schema || !node->parent->schema || (node->parent->schema->nodetype & LYD_NODE_ANY)) {
return LY_SUCCESS;
}
parent = (struct lyd_node_inner *)node->parent;
if (!parent->children_ht) {
u = 0;
LY_LIST_FOR(parent->child, iter) {
if (iter->schema) {
++u;
}
}
if (u >= LYD_HT_MIN_ITEMS) {
parent->children_ht = lyht_new(lyht_get_fixed_size(u), sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
LY_LIST_FOR(parent->child, iter) {
if (iter->schema) {
LY_CHECK_RET(lyd_insert_hash_add(parent->children_ht, iter, 1));
}
}
}
} else {
LY_CHECK_RET(lyd_insert_hash_add(parent->children_ht, node, 0));
}
return LY_SUCCESS;
}
void
lyd_unlink_hash(struct lyd_node *node)
{
struct lyd_node_inner *parent;
uint32_t hash;
if (!node->parent || !node->schema || !node->parent->schema || !((struct lyd_node_inner *)node->parent)->children_ht) {
return;
}
parent = (struct lyd_node_inner *)node->parent;
if (lyht_remove(parent->children_ht, &node, node->hash)) {
LOGINT(LYD_CTX(node));
return;
}
if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (!node->prev->next || (node->prev->schema != node->schema))) {
hash = lyht_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
hash = lyht_hash_multi(hash, node->schema->name, strlen(node->schema->name));
hash = lyht_hash_multi(hash, NULL, 0);
if (lyht_remove(parent->children_ht, &node, hash)) {
LOGINT(LYD_CTX(node));
return;
}
if (node->next && (node->next->schema == node->schema)) {
if (lyht_insert(parent->children_ht, &node->next, hash, NULL)) {
LOGINT(LYD_CTX(node));
return;
}
}
}
}