00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2002--2007 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CUCON_HMAP_H 00019 #define CUCON_HMAP_H 00020 00021 #include <cucon/fwd.h> 00022 #include <cu/clos.h> 00023 00024 CU_BEGIN_DECLARATIONS 00025 /** \defgroup cucon_hmap_h cucon/hmap.h: General-Purpose Hash Map 00026 ** @{ \ingroup cucon_maps_and_sets_mod 00027 ** 00028 ** Defined here is a hash map where the keys are pointers with associated 00029 ** client-provided equality and hash functions. The values are arbitrary 00030 ** sized slots, but shortcuts for pointer-valued maps are provided. 00031 ** 00032 ** \see cucon_hset_h 00033 ** \see cucon_pmap_h 00034 **/ 00035 00036 typedef struct cucon_hmap_node *cucon_hmap_node_t; 00037 struct cucon_hmap_node 00038 { 00039 cucon_hmap_node_t next; 00040 void const *key; 00041 /* value data */ 00042 }; 00043 00044 struct cucon_hmap 00045 { 00046 cu_clop(eq, cu_bool_t, void const *, void const *); 00047 cu_clop(hash, cu_hash_t, void const *); 00048 cucon_hmap_node_t *table; 00049 int size; 00050 cu_hash_t mask; 00051 struct cucon_hmap_node tail; 00052 }; 00053 00054 /** Initialise \a map as a hash set over objects with equality \a eq and hash 00055 ** function \a hash. */ 00056 void cucon_hmap_init(cucon_hmap_t map, 00057 cu_clop(eq, cu_bool_t, void const *, void const *), 00058 cu_clop(hash, cu_hash_t, void const *)); 00059 00060 /** Return a hash set over objects with equality defined by \a eq and hash 00061 ** function \a hash. */ 00062 cucon_hmap_t cucon_hmap_new(cu_clop(eq, cu_bool_t, void const *, void const *), 00063 cu_clop(hash, cu_hash_t, void const *)); 00064 00065 /** Erase all entries in \a hash. */ 00066 void cucon_hmap_clear(cucon_hmap_t); 00067 00068 /** The number of elements of \a map. */ 00069 CU_SINLINE size_t 00070 cucon_hmap_card(cucon_hmap_t map) { return map->size; } 00071 00072 /** True iff \a map is empty. */ 00073 CU_SINLINE cu_bool_t 00074 cucon_hmap_is_empty(cucon_hmap_t map) 00075 { return map->size != 0; } 00076 00077 /** If an object equal to \a key is in \a map, return its value slot, else 00078 ** return \c NULL. */ 00079 void *cucon_hmap_find_mem(cucon_hmap_t map, void const *key); 00080 00081 /** If an object equal to \a key is in \a map, assume it maps to a slot 00082 ** containing a pointer, and return the pointer, otherwise return \c NULL. */ 00083 void *cucon_hmap_find_ptr(cucon_hmap_t map, void const *key); 00084 00085 /** If \a key is in \a map, return false and set \c *\a slot to its value slot, 00086 ** else return true and associate \a key with \a slot_size bytes of value slot 00087 ** assigned to \c *\a slot. */ 00088 cu_bool_t cucon_hmap_insert_mem(cucon_hmap_t map, void const *key, 00089 size_t slot_size, cu_ptr_ptr_t slot); 00090 00091 /** If \a key has a mapping in \a map, return the slot and erase it, otherwise 00092 ** return \c NULL. */ 00093 void *cucon_hmap_pop_mem(cucon_hmap_t map, void const *key); 00094 00095 /** If \a key has a mapping in \a map, return the single pointer which is 00096 ** assumed to be stored in the slot and delete the mapping, otherwise return 00097 ** \c NULL. */ 00098 void *cucon_hmap_pop_ptr(cucon_hmap_t map, void const *key); 00099 00100 /** Delete the mapping of \a key from \a map if it exists and return true, 00101 ** otherwise return false. */ 00102 CU_SINLINE cu_bool_t 00103 cucon_hmap_erase(cucon_hmap_t map, void const *key) 00104 { return cucon_hmap_pop_mem(map, key) != NULL; } 00105 00106 /** Same as \ref cucon_hmap_pop_mem, except that the capacity is kept constant. 00107 ** Use in conjunction with \ref cucon_hmap_set_capacity as an optimisation. */ 00108 void *cucon_hmap_isocap_pop_mem(cucon_hmap_t map, void const *key); 00109 00110 /** Same as \ref cucon_hmap_pop_ptr, except that the capacity is kept constant. 00111 ** Use in conjunction with \ref cucon_hmap_set_capacity as an optimisation. */ 00112 void *cucon_hmap_isocap_pop_ptr(cucon_hmap_t map, void const *key); 00113 00114 /** Same as \ref cucon_hmap_erase, except that the capacity is kept constant. 00115 ** Use in conjunction with \ref cucon_hmap_set_capacity as an optimisation. */ 00116 CU_SINLINE cu_bool_t 00117 cucon_hmap_isocap_erase(cucon_hmap_t map, void const *key) 00118 { return cucon_hmap_isocap_pop_mem(map, key) != NULL; } 00119 00120 /** Set the capacity of \a map to \a cap, which must be a power of 2. This is 00121 ** used either as a preparation for subsequent insertions or as a final step 00122 ** after a series of calls to the "isocap" functions. It is merely an 00123 ** optimisation to avoid unnecessary intermediate adjustments of the capacity 00124 ** when the final cardinality is known. */ 00125 void cucon_hmap_set_capacity(cucon_hmap_t map, size_t cap); 00126 00127 cu_bool_t cucon_hmap_conj_keys(cucon_hmap_t map, 00128 cu_clop(f, cu_bool_t, void const *)); 00129 00130 cu_bool_t cucon_hmap_conj_mem(cucon_hmap_t map, 00131 cu_clop(f, cu_bool_t, void const *, void *)); 00132 00133 #if 0 00134 struct cucon_hmap_itr 00135 { 00136 cucon_hmap_node_t *node_head; 00137 cucon_hmap_node_t node; 00138 }; 00139 #endif 00140 00141 /** @} */ 00142 00143 #if defined(CU_COMPAT) && CU_COMPAT < 20091116 00144 # define cucon_hmap_size cucon_hmap_card 00145 # define cucon_hmap_erase_keep_capacity cucon_hmap_isocap_pop_mem 00146 #endif 00147 00148 CU_END_DECLARATIONS 00149 00150 #endif