|  | /*****************************************************************************\ | 
|  | *  xtree.c - functions used for hash table manament | 
|  | ***************************************************************************** | 
|  | *  Copyright (C) 2012 CEA/DAM/DIF | 
|  | * | 
|  | *  This file is part of Slurm, a resource management program. | 
|  | *  For details, see <https://slurm.schedmd.com/>. | 
|  | *  Please also read the included file: DISCLAIMER. | 
|  | * | 
|  | *  Slurm is free software; you can redistribute it and/or modify it under | 
|  | *  the terms of the GNU General Public License as published by the Free | 
|  | *  Software Foundation; either version 2 of the License, or (at your option) | 
|  | *  any later version. | 
|  | * | 
|  | *  In addition, as a special exception, the copyright holders give permission | 
|  | *  to link the code of portions of this program with the OpenSSL library under | 
|  | *  certain conditions as described in each individual source file, and | 
|  | *  distribute linked combinations including the two. You must obey the GNU | 
|  | *  General Public License in all respects for all of the code used other than | 
|  | *  OpenSSL. If you modify file(s) with this exception, you may extend this | 
|  | *  exception to your version of the file(s), but you are not obligated to do | 
|  | *  so. If you do not wish to do so, delete this exception statement from your | 
|  | *  version.  If you delete this exception statement from all source files in | 
|  | *  the program, then also delete it here. | 
|  | * | 
|  | *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY | 
|  | *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|  | *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more | 
|  | *  details. | 
|  | * | 
|  | *  You should have received a copy of the GNU General Public License along | 
|  | *  with Slurm; if not, write to the Free Software Foundation, Inc., | 
|  | *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA. | 
|  | \*****************************************************************************/ | 
|  |  | 
|  | #include "src/common/uthash.h" | 
|  | #include "src/common/xhash.h" | 
|  | #include "src/common/xmalloc.h" | 
|  | #include "src/common/xstring.h" | 
|  |  | 
|  | #if 0 | 
|  | /* undefine default allocators */ | 
|  | #undef uthash_malloc | 
|  | #undef uthash_free | 
|  |  | 
|  | /* re-define them using slurm's ones */ | 
|  | #define uthash_malloc(sz) xmalloc(sz) | 
|  | #define uthash_free(ptr, sz) xfree(ptr) | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * FIXME: | 
|  | * A pre-malloced array of xhash_item_t could be associated to | 
|  | * the xhash_table in order to speed up the xhash_add function. | 
|  | * The default array size could be something like 10% of the | 
|  | * provided table_size (hash table are commonly defined larger | 
|  | * than necessary to avoid shared keys and usage of linked list) | 
|  | */ | 
|  |  | 
|  | typedef struct xhash_item_st { | 
|  | void*		item;    /* user item                               */ | 
|  | UT_hash_handle	hh;      /* make this structure hashable by uthash  */ | 
|  | } xhash_item_t; | 
|  |  | 
|  | struct xhash_st { | 
|  | uint32_t		count;    /* user items count                */ | 
|  | xhash_freefunc_t	freefunc; /* function used to free items     */ | 
|  | xhash_item_t*		ht;       /* hash table                      */ | 
|  | xhash_idfunc_t		identify; /* function returning a unique str | 
|  | key */ | 
|  | }; | 
|  |  | 
|  | xhash_t *xhash_init(xhash_idfunc_t idfunc, xhash_freefunc_t freefunc) | 
|  | { | 
|  | xhash_t* table = NULL; | 
|  | if (!idfunc) | 
|  | return NULL; | 
|  | table = xmalloc(sizeof(xhash_t)); | 
|  | table->ht = NULL; /* required by uthash */ | 
|  | table->count = 0; | 
|  | table->identify = idfunc; | 
|  | table->freefunc = freefunc; | 
|  | return table; | 
|  | } | 
|  |  | 
|  | static xhash_item_t* xhash_find(xhash_t* table, const char* key, uint32_t len) | 
|  | { | 
|  | xhash_item_t* hash_item = NULL; | 
|  |  | 
|  | if (!table || !key) | 
|  | return NULL; | 
|  | HASH_FIND(hh, table->ht, key, len, hash_item); | 
|  | return hash_item; | 
|  | } | 
|  |  | 
|  | void* xhash_get(xhash_t* table, const char* key, uint32_t key_len) | 
|  | { | 
|  | xhash_item_t* item = xhash_find(table, key, key_len); | 
|  | if (!item) | 
|  | return NULL; | 
|  | return item->item; | 
|  | } | 
|  |  | 
|  | void* xhash_get_str(xhash_t* table, const char* key) | 
|  | { | 
|  | return xhash_get(table, key, strlen(key)); | 
|  | } | 
|  |  | 
|  | void* xhash_add(xhash_t* table, void* item) | 
|  | { | 
|  | xhash_item_t* hash_item = NULL; | 
|  | const char *key = NULL; | 
|  | uint32_t keylen = 0; | 
|  |  | 
|  | if (!table || !item) | 
|  | return NULL; | 
|  | hash_item = xmalloc(sizeof(xhash_item_t)); | 
|  | hash_item->item    = item; | 
|  | table->identify(item, &key, &keylen); | 
|  | HASH_ADD_KEYPTR(hh, table->ht, key, keylen, hash_item); | 
|  | ++table->count; | 
|  | return hash_item->item; | 
|  | } | 
|  |  | 
|  | void* xhash_pop(xhash_t* table, const char* key, uint32_t len) | 
|  | { | 
|  | void* item_item; | 
|  | xhash_item_t* item = xhash_find(table, key, len); | 
|  | if (!item) | 
|  | return NULL; | 
|  | item_item = item->item; | 
|  | HASH_DELETE(hh, table->ht, item); | 
|  | xfree(item); | 
|  | --table->count; | 
|  | return item_item; | 
|  | } | 
|  |  | 
|  | void* xhash_pop_str(xhash_t* table, const char* key) | 
|  | { | 
|  | return xhash_pop(table, key, strlen(key)); | 
|  | } | 
|  |  | 
|  | void xhash_delete(xhash_t* table, const char* key, uint32_t len) | 
|  | { | 
|  | if (!table || !key || !len) | 
|  | return; | 
|  | void* item_item = xhash_pop(table, key, len); | 
|  | if (table->freefunc) | 
|  | table->freefunc(item_item); | 
|  | } | 
|  |  | 
|  | void xhash_delete_str(xhash_t* table, const char* key) | 
|  | { | 
|  | return xhash_delete(table, key, strlen(key)); | 
|  | } | 
|  |  | 
|  | uint32_t xhash_count(xhash_t* table) | 
|  | { | 
|  | if (!table) | 
|  | return 0; | 
|  | return table->count; | 
|  | } | 
|  |  | 
|  | void xhash_walk(xhash_t* table, | 
|  | void (*callback)(void* item, void* arg), | 
|  | void* arg) | 
|  | { | 
|  | xhash_item_t* current_item = NULL; | 
|  | xhash_item_t* tmp = NULL; | 
|  | if (!table || !callback) | 
|  | return; | 
|  | HASH_ITER(hh, table->ht, current_item, tmp) { | 
|  | callback(current_item->item, arg); | 
|  | } | 
|  | } | 
|  |  | 
|  | void xhash_clear(xhash_t* table) | 
|  | { | 
|  | xhash_item_t* current_item = NULL; | 
|  | xhash_item_t* tmp = NULL; | 
|  |  | 
|  | if (!table) | 
|  | return; | 
|  | HASH_ITER(hh, table->ht, current_item, tmp) { | 
|  | HASH_DEL(table->ht, current_item); | 
|  | if (table->freefunc) | 
|  | table->freefunc(current_item->item); | 
|  | xfree(current_item); | 
|  | } | 
|  |  | 
|  | table->count = 0; | 
|  | } | 
|  |  | 
|  | void xhash_free_ptr(xhash_t** table) | 
|  | { | 
|  | if (!table || !*table) | 
|  | return; | 
|  | xhash_clear(*table); | 
|  | xfree(*table); | 
|  | } |