Coverage Report

Created: 2026-09-20 06:25

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