2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 18:19:42 +00:00
bind/lib/isc/symtab.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

293 lines
7.1 KiB
C
Raw Permalink Normal View History

1998-12-18 19:06:16 +00:00
/*
2011-11-30 23:46:25 +00:00
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
1998-12-18 19:06:16 +00:00
*
* SPDX-License-Identifier: MPL-2.0
*
1998-12-18 19:06:16 +00:00
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
1998-12-18 19:06:16 +00:00
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
1998-12-18 19:06:16 +00:00
*/
/*! \file */
2000-06-22 22:00:42 +00:00
#include <stdbool.h>
1998-12-18 19:06:16 +00:00
#include <isc/ascii.h>
#include <isc/fxhash.h>
#include <isc/hash.h>
#include <isc/hashmap.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/string.h>
1998-12-18 19:06:16 +00:00
#include <isc/symtab.h>
1999-12-16 22:24:22 +00:00
#include <isc/util.h>
1998-12-18 21:17:37 +00:00
1998-12-18 19:06:16 +00:00
typedef struct elt {
void *key;
size_t size;
1998-12-18 19:06:16 +00:00
unsigned int type;
1998-12-18 21:17:37 +00:00
isc_symvalue_t value;
1998-12-18 19:06:16 +00:00
} elt_t;
/* 4 bits means 16 entries at creation, which matches the common use of
* symtab */
#define ISC_SYMTAB_INIT_HASH_BITS 4
#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
1998-12-18 21:17:37 +00:00
1998-12-18 19:06:16 +00:00
struct isc_symtab {
1998-12-18 21:17:37 +00:00
/* Unlocked. */
unsigned int magic;
1998-12-18 19:06:16 +00:00
isc_mem_t *mctx;
1998-12-18 21:17:37 +00:00
isc_symtabaction_t undefine_action;
void *undefine_arg;
isc_hashmap_t *hashmap;
bool case_sensitive;
1998-12-18 19:06:16 +00:00
};
static void
elt_destroy(isc_symtab_t *symtab, elt_t *elt) {
if (symtab->undefine_action != NULL) {
(symtab->undefine_action)(elt->key, elt->type, elt->value,
symtab->undefine_arg);
}
isc_mem_put(symtab->mctx, elt, sizeof(*elt));
}
1998-12-18 19:06:16 +00:00
void
isc_symtab_create(isc_mem_t *mctx, isc_symtabaction_t undefine_action,
void *undefine_arg, bool case_sensitive,
isc_symtab_t **symtabp) {
1998-12-18 19:06:16 +00:00
REQUIRE(mctx != NULL);
REQUIRE(symtabp != NULL && *symtabp == NULL);
isc_symtab_t *symtab = isc_mem_get(mctx, sizeof(*symtab));
*symtab = (isc_symtab_t){
.undefine_action = undefine_action,
.undefine_arg = undefine_arg,
.case_sensitive = case_sensitive,
.magic = SYMTAB_MAGIC,
};
isc_mem_attach(mctx, &symtab->mctx);
isc_hashmap_create(symtab->mctx, ISC_SYMTAB_INIT_HASH_BITS,
&symtab->hashmap);
1998-12-18 19:06:16 +00:00
*symtabp = symtab;
}
void
isc_symtab_destroy(isc_symtab_t **symtabp) {
REQUIRE(symtabp != NULL && VALID_SYMTAB(*symtabp));
1998-12-18 19:06:16 +00:00
isc_result_t result;
isc_hashmap_iter_t *it = NULL;
isc_symtab_t *symtab = *symtabp;
*symtabp = NULL;
1998-12-18 19:06:16 +00:00
1998-12-18 21:17:37 +00:00
symtab->magic = 0;
isc_hashmap_iter_create(symtab->hashmap, &it);
for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;
result = isc_hashmap_iter_delcurrent_next(it))
{
elt_t *elt = NULL;
isc_hashmap_iter_current(it, (void **)&elt);
elt_destroy(symtab, elt);
}
INSIST(result == ISC_R_NOMORE);
isc_hashmap_iter_destroy(&it);
isc_hashmap_destroy(&symtab->hashmap);
isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
1998-12-18 19:06:16 +00:00
}
static bool
elt__match(void *node, const void *key0, bool case_sensitive) {
const elt_t *elt = node;
const elt_t *key = key0;
1998-12-18 19:06:16 +00:00
if (elt->size != key->size) {
return false;
}
if (elt->type != key->type) {
return false;
}
1998-12-18 19:06:16 +00:00
if (case_sensitive) {
return memcmp(elt->key, key->key, key->size) == 0;
} else {
return isc_ascii_lowerequal(elt->key, key->key, key->size);
1998-12-18 19:06:16 +00:00
}
}
1998-12-18 19:06:16 +00:00
static bool
elt_match_case(void *node, const void *key) {
return elt__match(node, key, true);
1998-12-18 19:06:16 +00:00
}
static bool
elt_match_nocase(void *node, const void *key) {
return elt__match(node, key, false);
}
static inline uint32_t
elt_hash(elt_t *restrict elt, bool case_sensitive) {
const uint8_t *ptr = elt->key;
size_t len = elt->size;
return fx_hash_bytes(0, ptr, len, case_sensitive);
}
1998-12-18 19:06:16 +00:00
isc_result_t
isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
isc_symvalue_t *valuep) {
1998-12-18 21:17:37 +00:00
REQUIRE(VALID_SYMTAB(symtab));
REQUIRE(key != NULL);
REQUIRE(type != 0);
1998-12-18 21:17:37 +00:00
elt_t *found = NULL;
elt_t elt = {
.key = UNCONST(key),
.size = strlen(key),
.type = type,
};
uint32_t elt_hashval = elt_hash(&elt, symtab->case_sensitive);
isc_hashmap_match_fn elt_match = symtab->case_sensitive
? elt_match_case
: elt_match_nocase;
isc_result_t result = isc_hashmap_find(
symtab->hashmap, elt_hashval, elt_match, &elt, (void **)&found);
if (result == ISC_R_SUCCESS) {
SET_IF_NOT_NULL(valuep, found->value);
}
return result;
}
1998-12-18 19:06:16 +00:00
isc_result_t
isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
1998-12-19 00:13:59 +00:00
isc_symvalue_t value, isc_symexists_t exists_policy) {
return isc_symtab_define_and_return(symtab, key, type, value,
exists_policy, NULL);
}
1998-12-18 19:06:16 +00:00
isc_result_t
isc_symtab_define_and_return(isc_symtab_t *symtab, const char *key,
unsigned int type, isc_symvalue_t value,
isc_symexists_t exists_policy,
isc_symvalue_t *valuep) {
1998-12-18 21:17:37 +00:00
REQUIRE(VALID_SYMTAB(symtab));
REQUIRE(key != NULL);
REQUIRE(type != 0);
1998-12-18 21:17:37 +00:00
isc_result_t result;
elt_t *found = NULL;
elt_t *elt = isc_mem_get(symtab->mctx, sizeof(*elt));
*elt = (elt_t){
.key = UNCONST(key),
.size = strlen(key),
.type = type,
.value = value,
};
uint32_t elt_hashval = elt_hash(elt, symtab->case_sensitive);
isc_hashmap_match_fn elt_match = symtab->case_sensitive
? elt_match_case
: elt_match_nocase;
again:
result = isc_hashmap_add(symtab->hashmap, elt_hashval, elt_match, elt,
(void *)elt, (void *)&found);
if (result == ISC_R_SUCCESS) {
SET_IF_NOT_NULL(valuep, elt->value);
return ISC_R_SUCCESS;
1998-12-19 00:13:59 +00:00
}
switch (exists_policy) {
case isc_symexists_reject:
SET_IF_NOT_NULL(valuep, found->value);
isc_mem_put(symtab->mctx, elt, sizeof(*elt));
return ISC_R_EXISTS;
case isc_symexists_replace:
result = isc_hashmap_delete(symtab->hashmap, elt_hashval,
elt_match, elt);
INSIST(result == ISC_R_SUCCESS);
elt_destroy(symtab, found);
goto again;
default:
UNREACHABLE();
}
1998-12-18 19:06:16 +00:00
return ISC_R_SUCCESS;
}
isc_result_t
isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
1998-12-18 21:17:37 +00:00
REQUIRE(VALID_SYMTAB(symtab));
REQUIRE(key != NULL);
REQUIRE(type != 0);
1998-12-18 21:17:37 +00:00
elt_t *found = NULL;
elt_t elt = {
.key = UNCONST(key),
.size = strlen(key),
.type = type,
};
uint32_t elt_hashval = elt_hash(&elt, symtab->case_sensitive);
isc_hashmap_match_fn elt_match = symtab->case_sensitive
? elt_match_case
: elt_match_nocase;
isc_result_t result = isc_hashmap_find(
symtab->hashmap, elt_hashval, elt_match, &elt, (void **)&found);
if (result == ISC_R_NOTFOUND) {
1998-12-18 19:06:16 +00:00
return ISC_R_NOTFOUND;
}
1998-12-18 19:06:16 +00:00
result = isc_hashmap_delete(symtab->hashmap, elt_hashval, elt_match,
&elt);
INSIST(result == ISC_R_SUCCESS);
elt_destroy(symtab, found);
1998-12-18 19:06:16 +00:00
return ISC_R_SUCCESS;
}
unsigned int
isc_symtab_count(isc_symtab_t *symtab) {
REQUIRE(VALID_SYMTAB(symtab));
return isc_hashmap_count(symtab->hashmap);
}
void
isc_symtab_foreach(isc_symtab_t *symtab, isc_symtabforeachaction_t action,
void *arg) {
REQUIRE(VALID_SYMTAB(symtab));
REQUIRE(action != NULL);
isc_result_t result;
isc_hashmap_iter_t *it = NULL;
isc_hashmap_iter_create(symtab->hashmap, &it);
for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;) {
elt_t *elt = NULL;
isc_hashmap_iter_current(it, (void **)&elt);
if ((action)(elt->key, elt->type, elt->value, arg)) {
elt_destroy(symtab, elt);
result = isc_hashmap_iter_delcurrent_next(it);
} else {
result = isc_hashmap_iter_next(it);
}
}
INSIST(result == ISC_R_NOMORE);
isc_hashmap_iter_destroy(&it);
}