]>
Commit | Line | Data |
---|---|---|
c801d85f | 1 | ///////////////////////////////////////////////////////////////////////////// |
7cb32b4b | 2 | // Name: src/common/hash.cpp |
c801d85f KB |
3 | // Purpose: wxHashTable implementation |
4 | // Author: Julian Smart | |
bcaa23de | 5 | // Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() |
c801d85f KB |
6 | // Created: 01/02/97 |
7 | // RCS-ID: $Id$ | |
55d99c7a | 8 | // Copyright: (c) Julian Smart |
65571936 | 9 | // Licence: wxWindows licence |
c801d85f KB |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
bcaa23de VZ |
12 | // ============================================================================ |
13 | // declarations | |
14 | // ============================================================================ | |
15 | ||
16 | // ---------------------------------------------------------------------------- | |
17 | // headers | |
18 | // ---------------------------------------------------------------------------- | |
19 | ||
c801d85f KB |
20 | // For compilers that support precompilation, includes "wx.h". |
21 | #include "wx/wxprec.h" | |
22 | ||
23 | #ifdef __BORLANDC__ | |
8ecff181 | 24 | #pragma hdrstop |
c801d85f KB |
25 | #endif |
26 | ||
27 | #ifndef WX_PRECOMP | |
32d4c30a | 28 | #include "wx/hash.h" |
c801d85f KB |
29 | #endif |
30 | ||
1a6d9c76 MB |
31 | wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value, |
32 | wxHashTableBase* table ) | |
33 | : m_value( value ), m_hashPtr( table ) | |
34 | { | |
35 | m_key.integer = key; | |
36 | } | |
37 | ||
0518029c | 38 | wxHashTableBase_Node::wxHashTableBase_Node( const wxString& key, void* value, |
1a6d9c76 MB |
39 | wxHashTableBase* table ) |
40 | : m_value( value ), m_hashPtr( table ) | |
41 | { | |
0518029c | 42 | m_key.string = new wxString(key); |
1a6d9c76 MB |
43 | } |
44 | ||
45 | wxHashTableBase_Node::~wxHashTableBase_Node() | |
46 | { | |
47 | if( m_hashPtr ) m_hashPtr->DoRemoveNode( this ); | |
48 | } | |
49 | ||
50 | // | |
51 | ||
52 | wxHashTableBase::wxHashTableBase() | |
53 | : m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ), | |
54 | m_deleteContents( false ) | |
55 | { | |
56 | } | |
57 | ||
1a6d9c76 MB |
58 | void wxHashTableBase::Create( wxKeyType keyType, size_t size ) |
59 | { | |
60 | m_keyType = keyType; | |
61 | m_size = size; | |
62 | m_table = new wxHashTableBase_Node*[ m_size ]; | |
63 | ||
64 | for( size_t i = 0; i < m_size; ++i ) | |
65 | m_table[i] = NULL; | |
66 | } | |
67 | ||
68 | void wxHashTableBase::Clear() | |
69 | { | |
70 | for( size_t i = 0; i < m_size; ++i ) | |
71 | { | |
72 | Node* end = m_table[i]; | |
73 | ||
74 | if( end == NULL ) | |
75 | continue; | |
76 | ||
77 | Node *curr, *next = end->GetNext(); | |
78 | ||
79 | do | |
80 | { | |
81 | curr = next; | |
82 | next = curr->GetNext(); | |
83 | ||
84 | DoDestroyNode( curr ); | |
85 | ||
86 | delete curr; | |
87 | } | |
88 | while( curr != end ); | |
89 | ||
90 | m_table[i] = NULL; | |
91 | } | |
92 | ||
93 | m_count = 0; | |
94 | } | |
95 | ||
96 | void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node ) | |
97 | { | |
98 | size_t bucket = ( m_keyType == wxKEY_INTEGER ? | |
99 | node->m_key.integer : | |
0518029c | 100 | MakeKey( *node->m_key.string ) ) % m_size; |
1a6d9c76 MB |
101 | |
102 | if( node->GetNext() == node ) | |
103 | { | |
104 | // single-node chain (common case) | |
105 | m_table[bucket] = NULL; | |
106 | } | |
107 | else | |
108 | { | |
109 | Node *start = m_table[bucket], *curr; | |
110 | Node* prev = start; | |
111 | ||
112 | for( curr = prev->GetNext(); curr != node; | |
f803b25b | 113 | prev = curr, curr = curr->GetNext() ) ; |
1a6d9c76 MB |
114 | |
115 | DoUnlinkNode( bucket, node, prev ); | |
116 | } | |
117 | ||
118 | DoDestroyNode( node ); | |
119 | } | |
120 | ||
121 | void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node ) | |
122 | { | |
123 | // if it is called from DoRemoveNode, node has already been | |
124 | // removed, from other places it does not matter | |
125 | node->m_hashPtr = NULL; | |
126 | ||
127 | if( m_keyType == wxKEY_STRING ) | |
0518029c | 128 | delete node->m_key.string; |
1a6d9c76 MB |
129 | if( m_deleteContents ) |
130 | DoDeleteContents( node ); | |
131 | } | |
132 | ||
133 | void wxHashTableBase::Destroy() | |
134 | { | |
135 | Clear(); | |
136 | ||
137 | delete[] m_table; | |
138 | ||
139 | m_table = NULL; | |
140 | m_size = 0; | |
141 | } | |
142 | ||
143 | void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node ) | |
144 | { | |
145 | if( m_table[bucket] == NULL ) | |
146 | { | |
147 | m_table[bucket] = node->m_next = node; | |
148 | } | |
149 | else | |
150 | { | |
151 | Node *prev = m_table[bucket]; | |
152 | Node *next = prev->m_next; | |
153 | ||
154 | prev->m_next = node; | |
155 | node->m_next = next; | |
156 | m_table[bucket] = node; | |
157 | } | |
158 | ||
159 | ++m_count; | |
160 | } | |
161 | ||
162 | void wxHashTableBase::DoPut( long key, long hash, void* data ) | |
163 | { | |
164 | wxASSERT( m_keyType == wxKEY_INTEGER ); | |
165 | ||
166 | size_t bucket = size_t(hash) % m_size; | |
167 | Node* node = new wxHashTableBase_Node( key, data, this ); | |
168 | ||
169 | DoInsertNode( bucket, node ); | |
170 | } | |
171 | ||
0518029c | 172 | void wxHashTableBase::DoPut( const wxString& key, long hash, void* data ) |
1a6d9c76 MB |
173 | { |
174 | wxASSERT( m_keyType == wxKEY_STRING ); | |
175 | ||
176 | size_t bucket = size_t(hash) % m_size; | |
177 | Node* node = new wxHashTableBase_Node( key, data, this ); | |
178 | ||
179 | DoInsertNode( bucket, node ); | |
180 | } | |
181 | ||
182 | void* wxHashTableBase::DoGet( long key, long hash ) const | |
183 | { | |
184 | wxASSERT( m_keyType == wxKEY_INTEGER ); | |
185 | ||
186 | size_t bucket = size_t(hash) % m_size; | |
187 | ||
188 | if( m_table[bucket] == NULL ) | |
189 | return NULL; | |
190 | ||
191 | Node *first = m_table[bucket]->GetNext(), | |
192 | *curr = first; | |
193 | ||
194 | do | |
195 | { | |
196 | if( curr->m_key.integer == key ) | |
197 | return curr->m_value; | |
198 | ||
199 | curr = curr->GetNext(); | |
200 | } | |
201 | while( curr != first ); | |
202 | ||
203 | return NULL; | |
204 | } | |
205 | ||
0518029c | 206 | void* wxHashTableBase::DoGet( const wxString& key, long hash ) const |
1a6d9c76 MB |
207 | { |
208 | wxASSERT( m_keyType == wxKEY_STRING ); | |
209 | ||
210 | size_t bucket = size_t(hash) % m_size; | |
211 | ||
212 | if( m_table[bucket] == NULL ) | |
213 | return NULL; | |
214 | ||
215 | Node *first = m_table[bucket]->GetNext(), | |
216 | *curr = first; | |
217 | ||
218 | do | |
219 | { | |
0518029c | 220 | if( *curr->m_key.string == key ) |
1a6d9c76 MB |
221 | return curr->m_value; |
222 | ||
223 | curr = curr->GetNext(); | |
224 | } | |
225 | while( curr != first ); | |
226 | ||
227 | return NULL; | |
228 | } | |
229 | ||
230 | void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node, | |
231 | wxHashTableBase_Node* prev ) | |
232 | { | |
233 | if( node == m_table[bucket] ) | |
234 | m_table[bucket] = prev; | |
235 | ||
236 | if( prev == node && prev == node->GetNext() ) | |
237 | m_table[bucket] = NULL; | |
238 | else | |
239 | prev->m_next = node->m_next; | |
240 | ||
241 | DoDestroyNode( node ); | |
242 | --m_count; | |
243 | } | |
244 | ||
245 | void* wxHashTableBase::DoDelete( long key, long hash ) | |
246 | { | |
247 | wxASSERT( m_keyType == wxKEY_INTEGER ); | |
248 | ||
249 | size_t bucket = size_t(hash) % m_size; | |
250 | ||
251 | if( m_table[bucket] == NULL ) | |
252 | return NULL; | |
253 | ||
254 | Node *first = m_table[bucket]->GetNext(), | |
255 | *curr = first, | |
256 | *prev = m_table[bucket]; | |
257 | ||
258 | do | |
259 | { | |
260 | if( curr->m_key.integer == key ) | |
261 | { | |
262 | void* retval = curr->m_value; | |
263 | curr->m_value = NULL; | |
264 | ||
265 | DoUnlinkNode( bucket, curr, prev ); | |
266 | delete curr; | |
267 | ||
268 | return retval; | |
269 | } | |
270 | ||
271 | prev = curr; | |
272 | curr = curr->GetNext(); | |
273 | } | |
274 | while( curr != first ); | |
275 | ||
276 | return NULL; | |
277 | } | |
278 | ||
0518029c | 279 | void* wxHashTableBase::DoDelete( const wxString& key, long hash ) |
1a6d9c76 MB |
280 | { |
281 | wxASSERT( m_keyType == wxKEY_STRING ); | |
282 | ||
283 | size_t bucket = size_t(hash) % m_size; | |
284 | ||
285 | if( m_table[bucket] == NULL ) | |
286 | return NULL; | |
287 | ||
288 | Node *first = m_table[bucket]->GetNext(), | |
289 | *curr = first, | |
290 | *prev = m_table[bucket]; | |
291 | ||
292 | do | |
293 | { | |
0518029c | 294 | if( *curr->m_key.string == key ) |
1a6d9c76 MB |
295 | { |
296 | void* retval = curr->m_value; | |
297 | curr->m_value = NULL; | |
298 | ||
299 | DoUnlinkNode( bucket, curr, prev ); | |
300 | delete curr; | |
301 | ||
302 | return retval; | |
303 | } | |
304 | ||
305 | prev = curr; | |
306 | curr = curr->GetNext(); | |
307 | } | |
308 | while( curr != first ); | |
309 | ||
310 | return NULL; | |
311 | } | |
312 | ||
0518029c | 313 | long wxHashTableBase::MakeKey( const wxString& str ) |
1a6d9c76 MB |
314 | { |
315 | long int_key = 0; | |
316 | ||
0518029c VZ |
317 | const wxStringCharType *p = str.wx_str(); |
318 | while( *p ) | |
319 | int_key += *p++; | |
1a6d9c76 MB |
320 | |
321 | return int_key; | |
322 | } | |
323 | ||
2441fb44 VZ |
324 | // ---------------------------------------------------------------------------- |
325 | // wxHashTable | |
326 | // ---------------------------------------------------------------------------- | |
1a6d9c76 MB |
327 | |
328 | wxHashTable::wxHashTable( const wxHashTable& table ) | |
2441fb44 | 329 | : wxHashTableBase() |
1a6d9c76 MB |
330 | { |
331 | DoCopy( table ); | |
332 | } | |
333 | ||
334 | const wxHashTable& wxHashTable::operator=( const wxHashTable& table ) | |
335 | { | |
336 | Destroy(); | |
337 | DoCopy( table ); | |
338 | ||
339 | return *this; | |
340 | } | |
341 | ||
6aa33060 | 342 | void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) ) |
1a6d9c76 MB |
343 | { |
344 | Create( m_keyType, m_size ); | |
345 | ||
7cb32b4b | 346 | wxFAIL; |
1a6d9c76 MB |
347 | } |
348 | ||
349 | void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node ) | |
350 | { | |
351 | delete ((wxHashTable_Node*)node)->GetData(); | |
352 | } | |
353 | ||
354 | void wxHashTable::GetNextNode( size_t bucketStart ) | |
355 | { | |
356 | for( size_t i = bucketStart; i < m_size; ++i ) | |
357 | { | |
358 | if( m_table[i] != NULL ) | |
359 | { | |
360 | m_curr = ((Node*)m_table[i])->GetNext(); | |
361 | m_currBucket = i; | |
362 | return; | |
363 | } | |
364 | } | |
365 | ||
366 | m_curr = NULL; | |
367 | m_currBucket = 0; | |
368 | } | |
369 | ||
370 | wxHashTable::Node* wxHashTable::Next() | |
371 | { | |
372 | if( m_curr == NULL ) | |
373 | GetNextNode( 0 ); | |
374 | else | |
375 | { | |
376 | m_curr = m_curr->GetNext(); | |
377 | ||
378 | if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() ) | |
379 | GetNextNode( m_currBucket + 1 ); | |
380 | } | |
381 | ||
382 | return m_curr; | |
383 | } | |
384 |