blob: eec3c319c6043718e7ea782e8c2b96af727c9d52 [file] [log] [blame]
njn3e884182003-04-15 13:03:23 +00001
2/*--------------------------------------------------------------------*/
njnf69f9452005-07-03 17:53:11 +00003/*--- A separately-chained hash table. m_hashtable.c ---*/
njn3e884182003-04-15 13:03:23 +00004/*--------------------------------------------------------------------*/
5
6/*
njnb9c427c2004-12-01 14:14:42 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
njn3e884182003-04-15 13:03:23 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
njn3e884182003-04-15 13:03:23 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
njn81c00df2005-05-14 21:28:43 +000032#include "pub_core_hashtable.h"
njn132bfcc2005-06-04 19:16:06 +000033#include "pub_core_libcassert.h"
njnaf1d7df2005-06-11 01:31:52 +000034#include "pub_core_mallocfree.h"
njn3e884182003-04-15 13:03:23 +000035
36/*--------------------------------------------------------------------*/
37/*--- Declarations ---*/
38/*--------------------------------------------------------------------*/
39
njnb8824022005-07-03 17:10:04 +000040#define CHAIN_NO(key,tbl) (((UWord)(key)) % tbl->n_chains)
41
njnf69f9452005-07-03 17:53:11 +000042struct _VgHashTable {
njn246a9d22005-08-14 06:24:20 +000043 UInt n_chains; // should be prime
njn1af79722005-08-14 17:42:35 +000044 VgHashNode* iterNode; // current iterator node
45 UInt iterChain; // next chain to be traversed by the iterator
46 VgHashNode* chains[0]; // must be last field in the struct!
njnf69f9452005-07-03 17:53:11 +000047};
njn3e884182003-04-15 13:03:23 +000048
49/*--------------------------------------------------------------------*/
50/*--- Functions ---*/
51/*--------------------------------------------------------------------*/
52
njnb8824022005-07-03 17:10:04 +000053VgHashTable VG_(HT_construct)(UInt n_chains)
njn3e884182003-04-15 13:03:23 +000054{
njnce46c2a2003-07-21 10:52:07 +000055 /* Initialises to zero, ie. all entries NULL */
njnf69f9452005-07-03 17:53:11 +000056 SizeT sz = sizeof(struct _VgHashTable) + n_chains*sizeof(VgHashNode*);
57 VgHashTable table = VG_(calloc)(1, sz);
njnb8824022005-07-03 17:10:04 +000058 table->n_chains = n_chains;
njnf69f9452005-07-03 17:53:11 +000059 return table;
njn3e884182003-04-15 13:03:23 +000060}
61
62Int VG_(HT_count_nodes) ( VgHashTable table )
63{
64 VgHashNode* node;
65 UInt chain;
66 Int n = 0;
67
njnb8824022005-07-03 17:10:04 +000068 for (chain = 0; chain < table->n_chains; chain++)
69 for (node = table->chains[chain]; node != NULL; node = node->next)
njn3e884182003-04-15 13:03:23 +000070 n++;
71 return n;
72}
73
njnf69f9452005-07-03 17:53:11 +000074/* Puts a new, heap allocated VgHashNode, into the VgHashTable. Prepends
75 the node to the appropriate chain. */
njn246a9d22005-08-14 06:24:20 +000076void VG_(HT_add_node) ( VgHashTable table, void* vnode )
njn3e884182003-04-15 13:03:23 +000077{
njn246a9d22005-08-14 06:24:20 +000078 VgHashNode* node = (VgHashNode*)vnode;
njnf69f9452005-07-03 17:53:11 +000079 UInt chain = CHAIN_NO(node->key, table);
80 node->next = table->chains[chain];
81 table->chains[chain] = node;
njn3e884182003-04-15 13:03:23 +000082}
83
84/* Looks up a VgHashNode in the table. Also returns the address of
njn02bc4b82005-05-15 17:28:26 +000085 the previous node's 'next' pointer which allows it to be removed from the
njn3e884182003-04-15 13:03:23 +000086 list later without having to look it up again. */
njn246a9d22005-08-14 06:24:20 +000087void* VG_(HT_get_node) ( VgHashTable table, UWord key,
88 /*OUT*/VgHashNode*** next_ptr )
njn3e884182003-04-15 13:03:23 +000089{
90 VgHashNode *prev, *curr;
91 Int chain;
92
njnf69f9452005-07-03 17:53:11 +000093 chain = CHAIN_NO(key, table);
njn3e884182003-04-15 13:03:23 +000094
95 prev = NULL;
njnb8824022005-07-03 17:10:04 +000096 curr = table->chains[chain];
njn3e884182003-04-15 13:03:23 +000097 while (True) {
98 if (curr == NULL)
99 break;
100 if (key == curr->key)
101 break;
102 prev = curr;
103 curr = curr->next;
104 }
105
106 if (NULL == prev)
njnf69f9452005-07-03 17:53:11 +0000107 *next_ptr = & (table->chains[chain]);
njn3e884182003-04-15 13:03:23 +0000108 else
njnb8824022005-07-03 17:10:04 +0000109 *next_ptr = & (prev->next);
njn3e884182003-04-15 13:03:23 +0000110
111 return curr;
112}
113
njn34582fb2005-08-11 00:06:36 +0000114/* Looks up a VgHashNode in the table. Returns NULL if not found. */
njn246a9d22005-08-14 06:24:20 +0000115void* VG_(HT_lookup) ( VgHashTable table, UWord key )
njn34582fb2005-08-11 00:06:36 +0000116{
117 VgHashNode* curr = table->chains[ CHAIN_NO(key, table) ];
118
119 while (curr) {
120 if (key == curr->key) {
121 return curr;
122 }
123 curr = curr->next;
124 }
125 return NULL;
126}
127
128/* Removes a VgHashNode from the table. Returns NULL if not found. */
njn246a9d22005-08-14 06:24:20 +0000129void* VG_(HT_remove) ( VgHashTable table, UWord key )
njn34582fb2005-08-11 00:06:36 +0000130{
131 Int chain = CHAIN_NO(key, table);
132 VgHashNode* curr = table->chains[chain];
133 VgHashNode** prev_next_ptr = &(table->chains[chain]);
134
135 while (curr) {
136 if (key == curr->key) {
137 *prev_next_ptr = curr->next;
138 return curr;
139 }
140 prev_next_ptr = &(curr->next);
141 curr = curr->next;
142 }
143 return NULL;
144}
145
njn3e884182003-04-15 13:03:23 +0000146/* Allocates a suitably-sized array, copies all the malloc'd block
njn06072ec2003-09-30 15:35:13 +0000147 shadows into it, then returns both the array and the size of it. This is
148 used by the memory-leak detector.
njn3e884182003-04-15 13:03:23 +0000149*/
njn06072ec2003-09-30 15:35:13 +0000150VgHashNode** VG_(HT_to_array) ( VgHashTable table, /*OUT*/ UInt* n_shadows )
njn3e884182003-04-15 13:03:23 +0000151{
152 UInt i, j;
153 VgHashNode** arr;
154 VgHashNode* node;
155
156 *n_shadows = 0;
njnb8824022005-07-03 17:10:04 +0000157 for (i = 0; i < table->n_chains; i++) {
158 for (node = table->chains[i]; node != NULL; node = node->next) {
njn3e884182003-04-15 13:03:23 +0000159 (*n_shadows)++;
160 }
161 }
162 if (*n_shadows == 0)
163 return NULL;
164
165 arr = VG_(malloc)( *n_shadows * sizeof(VgHashNode*) );
166
167 j = 0;
njnb8824022005-07-03 17:10:04 +0000168 for (i = 0; i < table->n_chains; i++) {
169 for (node = table->chains[i]; node != NULL; node = node->next) {
njn3e884182003-04-15 13:03:23 +0000170 arr[j++] = node;
171 }
172 }
njn8372b7f2003-05-14 12:42:14 +0000173 vg_assert(j == *n_shadows);
njn3e884182003-04-15 13:03:23 +0000174
njn3e884182003-04-15 13:03:23 +0000175 return arr;
176}
177
178/* Return the first VgHashNode satisfying the predicate p. */
njn246a9d22005-08-14 06:24:20 +0000179void* VG_(HT_first_match) ( VgHashTable table,
180 Bool (*p) ( VgHashNode*, void* ),
181 void* d )
njn3e884182003-04-15 13:03:23 +0000182{
183 UInt i;
184 VgHashNode* node;
185
njnb8824022005-07-03 17:10:04 +0000186 for (i = 0; i < table->n_chains; i++)
187 for (node = table->chains[i]; node != NULL; node = node->next)
thughes4ad52d02004-06-27 17:37:21 +0000188 if ( p(node, d) )
njn3e884182003-04-15 13:03:23 +0000189 return node;
190
191 return NULL;
192}
193
thughes4ad52d02004-06-27 17:37:21 +0000194void VG_(HT_apply_to_all_nodes)( VgHashTable table,
195 void (*f)(VgHashNode*, void*),
196 void* d )
njn3e884182003-04-15 13:03:23 +0000197{
198 UInt i;
199 VgHashNode* node;
200
njnb8824022005-07-03 17:10:04 +0000201 for (i = 0; i < table->n_chains; i++) {
202 for (node = table->chains[i]; node != NULL; node = node->next) {
thughes4ad52d02004-06-27 17:37:21 +0000203 f(node, d);
njn3e884182003-04-15 13:03:23 +0000204 }
205 }
206}
207
njn1af79722005-08-14 17:42:35 +0000208void VG_(HT_ResetIter)(VgHashTable table)
209{
210 vg_assert(table);
211 table->iterNode = NULL;
212 table->iterChain = 0;
213}
214
215void* VG_(HT_Next)(VgHashTable table)
216{
217 Int i;
218 vg_assert(table);
219
220 if (table->iterNode && table->iterNode->next) {
221 table->iterNode = table->iterNode->next;
222 return table->iterNode;
223 }
224
225 for (i = table->iterChain; i < table->n_chains; i++) {
226 if (table->chains[i]) {
227 table->iterNode = table->chains[i];
228 table->iterChain = i + 1; // Next chain to be traversed
229 return table->iterNode;
230 }
231 }
232 return NULL;
233}
234
njn3e884182003-04-15 13:03:23 +0000235void VG_(HT_destruct)(VgHashTable table)
236{
sewardj755e1262005-12-24 15:33:32 +0000237 UInt i;
238 VgHashNode *node, *node_next;
njn3e884182003-04-15 13:03:23 +0000239
njnb8824022005-07-03 17:10:04 +0000240 for (i = 0; i < table->n_chains; i++) {
sewardj755e1262005-12-24 15:33:32 +0000241 for (node = table->chains[i]; node != NULL; node = node_next) {
242 node_next = node->next;
njn3e884182003-04-15 13:03:23 +0000243 VG_(free)(node);
244 }
245 }
246 VG_(free)(table);
247}
248
249/*--------------------------------------------------------------------*/
njn81c00df2005-05-14 21:28:43 +0000250/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000251/*--------------------------------------------------------------------*/