Coverage Report

Created: 2025-06-13 07:02

/src/xerces-c/src/xercesc/util/RefHash3KeysIdPool.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
/*
19
 * $Id: RefHash3KeysIdPool.c 883368 2009-11-23 15:28:19Z amassari $
20
 */
21
22
23
// ---------------------------------------------------------------------------
24
//  Include
25
// ---------------------------------------------------------------------------
26
#if defined(XERCES_TMPLSINC)
27
#include <xercesc/util/RefHash3KeysIdPool.hpp>
28
#endif
29
30
#include <xercesc/util/NullPointerException.hpp>
31
#include <assert.h>
32
#include <new>
33
34
XERCES_CPP_NAMESPACE_BEGIN
35
36
// ---------------------------------------------------------------------------
37
//  RefHash3KeysIdPool: Constructors and Destructor
38
// ---------------------------------------------------------------------------
39
template <class TVal, class THasher>
40
RefHash3KeysIdPool<TVal, THasher>::RefHash3KeysIdPool(
41
  const XMLSize_t modulus,
42
  const XMLSize_t initSize,
43
  MemoryManager* const manager)
44
45
    : fMemoryManager(manager)
46
    , fAdoptedElems(true)
47
    , fBucketList(0)
48
    , fHashModulus(modulus)
49
    , fIdPtrs(0)
50
    , fIdPtrsCount(initSize)
51
    , fIdCounter(0)
52
{
53
    initialize(modulus);
54
55
    //  Allocate the initial id pointers array. We don't have to zero them
56
    //  out since the fIdCounter value tells us which ones are valid. The
57
    //  zeroth element is never used (and represents an invalid pool id.)
58
    //
59
    if (!fIdPtrsCount)
60
        fIdPtrsCount = 256;
61
    fIdPtrs = (TVal**) fMemoryManager->allocate(fIdPtrsCount * sizeof(TVal*)); //new TVal*[fIdPtrsCount];
62
    fIdPtrs[0] = 0;
63
}
64
65
template <class TVal, class THasher>
66
RefHash3KeysIdPool<TVal, THasher>::RefHash3KeysIdPool(
67
  const XMLSize_t modulus,
68
  const THasher& hasher,
69
  const XMLSize_t initSize,
70
  MemoryManager* const manager)
71
72
    : fMemoryManager(manager)
73
    , fAdoptedElems(true)
74
    , fBucketList(0)
75
    , fHashModulus(modulus)
76
    , fIdPtrs(0)
77
    , fIdPtrsCount(initSize)
78
    , fIdCounter(0)
79
    , fHasher(hasher)
80
{
81
    initialize(modulus);
82
83
    //  Allocate the initial id pointers array. We don't have to zero them
84
    //  out since the fIdCounter value tells us which ones are valid. The
85
    //  zeroth element is never used (and represents an invalid pool id.)
86
    //
87
    if (!fIdPtrsCount)
88
        fIdPtrsCount = 256;
89
    fIdPtrs = (TVal**) fMemoryManager->allocate(fIdPtrsCount * sizeof(TVal*)); //new TVal*[fIdPtrsCount];
90
    fIdPtrs[0] = 0;
91
}
92
93
template <class TVal, class THasher>
94
RefHash3KeysIdPool<TVal, THasher>::RefHash3KeysIdPool(
95
  const XMLSize_t modulus,
96
  const bool adoptElems,
97
  const XMLSize_t initSize,
98
  MemoryManager* const manager)
99
100
15.3k
    : fMemoryManager(manager)
101
15.3k
    , fAdoptedElems(adoptElems)
102
15.3k
    , fBucketList(0)
103
15.3k
    , fHashModulus(modulus)
104
15.3k
    , fIdPtrs(0)
105
15.3k
    , fIdPtrsCount(initSize)
106
15.3k
    , fIdCounter(0)
107
108
15.3k
{
109
15.3k
    initialize(modulus);
110
111
    //  Allocate the initial id pointers array. We don't have to zero them
112
    //  out since the fIdCounter value tells us which ones are valid. The
113
    //  zeroth element is never used (and represents an invalid pool id.)
114
    //
115
15.3k
    if (!fIdPtrsCount)
116
0
        fIdPtrsCount = 256;
117
15.3k
    fIdPtrs = (TVal**) fMemoryManager->allocate(fIdPtrsCount * sizeof(TVal*)); //new TVal*[fIdPtrsCount];
118
15.3k
    fIdPtrs[0] = 0;
119
15.3k
}
120
121
template <class TVal, class THasher>
122
RefHash3KeysIdPool<TVal, THasher>::RefHash3KeysIdPool(
123
  const XMLSize_t modulus,
124
  const bool adoptElems,
125
  const THasher& hasher,
126
  const XMLSize_t initSize,
127
  MemoryManager* const manager)
128
129
    : fMemoryManager(manager)
130
    , fAdoptedElems(adoptElems)
131
    , fBucketList(0)
132
    , fHashModulus(modulus)
133
    , fIdPtrs(0)
134
    , fIdPtrsCount(initSize)
135
    , fIdCounter(0)
136
    , fHasher(hasher)
137
{
138
    initialize(modulus);
139
140
    //  Allocate the initial id pointers array. We don't have to zero them
141
    //  out since the fIdCounter value tells us which ones are valid. The
142
    //  zeroth element is never used (and represents an invalid pool id.)
143
    //
144
    if (!fIdPtrsCount)
145
        fIdPtrsCount = 256;
146
    fIdPtrs = (TVal**) fMemoryManager->allocate(fIdPtrsCount * sizeof(TVal*)); //new TVal*[fIdPtrsCount];
147
    fIdPtrs[0] = 0;
148
}
149
150
template <class TVal, class THasher>
151
void RefHash3KeysIdPool<TVal, THasher>::initialize(const XMLSize_t modulus)
152
15.3k
{
153
15.3k
    if (modulus == 0)
154
0
        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::HshTbl_ZeroModulus, fMemoryManager);
155
156
    // Allocate the bucket list and zero them
157
15.3k
    fBucketList = (RefHash3KeysTableBucketElem<TVal>**) fMemoryManager->allocate
158
15.3k
    (
159
15.3k
        fHashModulus * sizeof(RefHash3KeysTableBucketElem<TVal>*)
160
15.3k
    ); //new RefHash3KeysTableBucketElem<TVal>*[fHashModulus];
161
15.3k
    memset(fBucketList, 0, sizeof(fBucketList[0]) * fHashModulus);
162
15.3k
}
163
164
template <class TVal, class THasher>
165
RefHash3KeysIdPool<TVal, THasher>::~RefHash3KeysIdPool()
166
15.3k
{
167
15.3k
    removeAll();
168
169
    // Then delete the bucket list & hasher & id pointers list
170
15.3k
    fMemoryManager->deallocate(fIdPtrs); //delete [] fIdPtrs;
171
15.3k
    fIdPtrs = 0;
172
15.3k
    fMemoryManager->deallocate(fBucketList); //delete [] fBucketList;
173
15.3k
    fBucketList = 0;
174
15.3k
}
175
176
177
// ---------------------------------------------------------------------------
178
//  RefHash3KeysIdPool: Element management
179
// ---------------------------------------------------------------------------
180
template <class TVal, class THasher>
181
bool RefHash3KeysIdPool<TVal, THasher>::isEmpty() const
182
{
183
    // Just check the bucket list for non-empty elements
184
    for (XMLSize_t buckInd = 0; buckInd < fHashModulus; buckInd++)
185
    {
186
        if (fBucketList[buckInd] != 0)
187
            return false;
188
    }
189
    return true;
190
}
191
192
template <class TVal, class THasher>
193
bool RefHash3KeysIdPool<TVal, THasher>::
194
containsKey(const void* const key1, const int key2, const int key3) const
195
{
196
    XMLSize_t hashVal;
197
    const RefHash3KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, key3, hashVal);
198
    return (findIt != 0);
199
}
200
201
template <class TVal, class THasher>
202
void RefHash3KeysIdPool<TVal, THasher>::removeAll()
203
15.3k
{
204
15.3k
    if (fIdCounter == 0) return;
205
206
    // Clean up the buckets first
207
0
    for (XMLSize_t buckInd = 0; buckInd < fHashModulus; buckInd++)
208
0
    {
209
        // Get the bucket list head for this entry
210
0
        RefHash3KeysTableBucketElem<TVal>* curElem = fBucketList[buckInd];
211
0
        RefHash3KeysTableBucketElem<TVal>* nextElem;
212
0
        while (curElem)
213
0
        {
214
            // Save the next element before we hose this one
215
0
            nextElem = curElem->fNext;
216
217
            // If we adopted the data, then delete it too
218
            //    (Note:  the userdata hash table instance has data type of void *.
219
            //    This will generate compiler warnings here on some platforms, but they
220
            //    can be ignored since fAdoptedElements is false.
221
0
            if (fAdoptedElems)
222
0
                delete curElem->fData;
223
224
            // Then delete the current element and move forward
225
            // delete curElem;
226
            // destructor is empty...
227
            // curElem->~RefHash3KeysTableBucketElem();
228
0
            fMemoryManager->deallocate(curElem);
229
0
            curElem = nextElem;
230
0
        }
231
232
        // Clean out this entry
233
0
        fBucketList[buckInd] = 0;
234
0
    }
235
236
    // Reset the id counter
237
0
    fIdCounter = 0;
238
0
}
239
240
241
// ---------------------------------------------------------------------------
242
//  RefHash3KeysIdPool: Getters
243
// ---------------------------------------------------------------------------
244
template <class TVal, class THasher>
245
TVal*
246
RefHash3KeysIdPool<TVal, THasher>::getByKey(const void* const key1, const int key2, const int key3)
247
0
{
248
0
    XMLSize_t hashVal;
249
0
    RefHash3KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, key3, hashVal);
250
0
    if (!findIt)
251
0
        return 0;
252
0
    return findIt->fData;
253
0
}
254
255
template <class TVal, class THasher>
256
const TVal*
257
RefHash3KeysIdPool<TVal, THasher>::getByKey(const void* const key1, const int key2, const int key3) const
258
{
259
    XMLSize_t hashVal;
260
    const RefHash3KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, key3, hashVal);
261
    if (!findIt)
262
        return 0;
263
    return findIt->fData;
264
}
265
266
template <class TVal, class THasher>
267
TVal*
268
RefHash3KeysIdPool<TVal, THasher>::getById(const unsigned int elemId)
269
0
{
270
    // If its either zero or beyond our current id, its an error
271
0
    if (!elemId || (elemId > fIdCounter))
272
0
        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Pool_InvalidId, fMemoryManager);
273
274
0
    return fIdPtrs[elemId];
275
0
}
276
277
template <class TVal, class THasher>
278
const TVal*
279
RefHash3KeysIdPool<TVal, THasher>::getById(const unsigned int elemId) const
280
{
281
    // If its either zero or beyond our current id, its an error
282
    if (!elemId || (elemId > fIdCounter))
283
        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Pool_InvalidId, fMemoryManager);
284
285
    return fIdPtrs[elemId];
286
}
287
288
template <class TVal, class THasher>
289
MemoryManager* RefHash3KeysIdPool<TVal, THasher>::getMemoryManager() const
290
0
{
291
0
    return fMemoryManager;
292
0
}
293
294
template <class TVal, class THasher>
295
XMLSize_t RefHash3KeysIdPool<TVal, THasher>::getHashModulus() const
296
0
{
297
0
    return fHashModulus;
298
0
}
299
300
// ---------------------------------------------------------------------------
301
//  RefHash3KeysIdPool: Putters
302
// ---------------------------------------------------------------------------
303
template <class TVal, class THasher>
304
XMLSize_t
305
RefHash3KeysIdPool<TVal, THasher>::put(void* key1, int key2, int key3, TVal* const valueToAdopt)
306
0
{
307
    // First see if the key exists already
308
0
    XMLSize_t hashVal;
309
0
    XMLSize_t retId;
310
0
    RefHash3KeysTableBucketElem<TVal>* newBucket = findBucketElem(key1, key2, key3, hashVal);
311
312
    //
313
    //  If so,then update its value. If not, then we need to add it to
314
    //  the right bucket
315
    //
316
0
    if (newBucket)
317
0
    {
318
0
        retId = newBucket->fData->getId();
319
0
        if (fAdoptedElems)
320
0
            delete newBucket->fData;
321
0
        newBucket->fData = valueToAdopt;
322
0
        newBucket->fKey1 = key1;
323
0
        newBucket->fKey2 = key2;
324
0
        newBucket->fKey3 = key3;
325
0
    }
326
0
    else
327
0
    {
328
    // Revisit: the gcc compiler 2.95.x is generating an
329
    // internal compiler error message. So we use the default
330
    // memory manager for now.
331
#if defined (XML_GCC_VERSION) && (XML_GCC_VERSION < 29600)
332
        newBucket = new RefHash3KeysTableBucketElem<TVal>(key1, key2, key3, valueToAdopt, fBucketList[hashVal]);
333
#else
334
0
        newBucket =
335
0
            new (fMemoryManager->allocate(sizeof(RefHash3KeysTableBucketElem<TVal>)))
336
0
            RefHash3KeysTableBucketElem<TVal>(key1, key2, key3, valueToAdopt, fBucketList[hashVal]);
337
0
#endif
338
0
        fBucketList[hashVal] = newBucket;
339
340
        //
341
        //  Give this new one the next available id and add to the pointer list.
342
        //  Expand the list if that is now required.
343
        //
344
0
        if (fIdCounter + 1 == fIdPtrsCount)
345
0
        {
346
            // Create a new count 1.5 times larger and allocate a new array
347
0
            XMLSize_t newCount = (XMLSize_t)(fIdPtrsCount * 1.5);
348
0
            TVal** newArray = (TVal**) fMemoryManager->allocate
349
0
            (
350
0
                newCount * sizeof(TVal*)
351
0
            ); //new TVal*[newCount];
352
353
            // Copy over the old contents to the new array
354
0
            memcpy(newArray, fIdPtrs, fIdPtrsCount * sizeof(TVal*));
355
356
            // Ok, toss the old array and store the new data
357
0
            fMemoryManager->deallocate(fIdPtrs); //delete [] fIdPtrs;
358
0
            fIdPtrs = newArray;
359
0
            fIdPtrsCount = newCount;
360
0
        }
361
0
        retId = ++fIdCounter;
362
0
    }
363
364
0
    fIdPtrs[retId] = valueToAdopt;
365
366
    // Set the id on the passed element
367
0
    valueToAdopt->setId(retId);
368
369
    // Return the id that we gave to this element
370
0
    return retId;
371
0
}
372
373
// ---------------------------------------------------------------------------
374
//  RefHash3KeysIdPool: Private methods
375
// ---------------------------------------------------------------------------
376
template <class TVal, class THasher>
377
inline RefHash3KeysTableBucketElem<TVal>* RefHash3KeysIdPool<TVal, THasher>::
378
findBucketElem(const void* const key1, const int key2, const int key3, XMLSize_t& hashVal)
379
0
{
380
    // Hash the key
381
0
    hashVal = fHasher.getHashVal(key1, fHashModulus);
382
0
    assert(hashVal < fHashModulus);
383
384
    // Search that bucket for the key
385
0
    RefHash3KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
386
0
    while (curElem)
387
0
    {
388
0
        if((key2==curElem->fKey2) && (key3==curElem->fKey3) && (fHasher.equals(key1, curElem->fKey1)))
389
0
            return curElem;
390
391
0
        curElem = curElem->fNext;
392
0
    }
393
0
    return 0;
394
0
}
395
396
template <class TVal, class THasher>
397
inline const RefHash3KeysTableBucketElem<TVal>* RefHash3KeysIdPool<TVal, THasher>::
398
findBucketElem(const void* const key1, const int key2, const int key3, XMLSize_t& hashVal) const
399
{
400
    // Hash the key
401
    hashVal = fHasher.getHashVal(key1, fHashModulus);
402
    assert(hashVal < fHashModulus);
403
404
    // Search that bucket for the key
405
    const RefHash3KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
406
    while (curElem)
407
    {
408
        if((key2==curElem->fKey2) && (key3==curElem->fKey3) && (fHasher.equals(key1, curElem->fKey1)))
409
            return curElem;
410
411
        curElem = curElem->fNext;
412
    }
413
    return 0;
414
}
415
416
417
// ---------------------------------------------------------------------------
418
//  RefHash3KeysIdPoolEnumerator: Constructors and Destructor
419
// ---------------------------------------------------------------------------
420
template <class TVal, class THasher>
421
RefHash3KeysIdPoolEnumerator<TVal, THasher>::
422
RefHash3KeysIdPoolEnumerator(RefHash3KeysIdPool<TVal, THasher>* const toEnum
423
                             , const bool adopt
424
                             , MemoryManager* const manager)
425
0
    : fAdoptedElems(adopt), fCurIndex(0), fToEnum(toEnum), fMemoryManager(manager)
426
0
{
427
0
    if (!toEnum)
428
0
        ThrowXMLwithMemMgr(NullPointerException, XMLExcepts::CPtr_PointerIsZero, fMemoryManager);
429
430
0
    Reset();
431
0
    resetKey();
432
0
}
433
434
template <class TVal, class THasher>
435
RefHash3KeysIdPoolEnumerator<TVal, THasher>::~RefHash3KeysIdPoolEnumerator()
436
0
{
437
0
    if (fAdoptedElems)
438
0
        delete fToEnum;
439
0
}
440
441
template <class TVal, class THasher>
442
RefHash3KeysIdPoolEnumerator<TVal, THasher>::
443
RefHash3KeysIdPoolEnumerator(const RefHash3KeysIdPoolEnumerator<TVal, THasher>& toCopy) :
444
    XMLEnumerator<TVal>(toCopy)
445
    , XMemory(toCopy)
446
    , fAdoptedElems(toCopy.fAdoptedElems)
447
    , fCurIndex(toCopy.fCurIndex)
448
    , fToEnum(toCopy.fToEnum)
449
    , fCurElem(toCopy.fCurElem)
450
    , fCurHash(toCopy.fCurHash)
451
    , fMemoryManager(toCopy.fMemoryManager)
452
{
453
}
454
455
// ---------------------------------------------------------------------------
456
//  RefHash3KeysIdPoolEnumerator: Enum interface
457
// ---------------------------------------------------------------------------
458
template <class TVal, class THasher>
459
bool RefHash3KeysIdPoolEnumerator<TVal, THasher>::hasMoreElements() const
460
0
{
461
    // If our index is zero or past the end, then we are done
462
0
    if (!fCurIndex || (fCurIndex > fToEnum->fIdCounter))
463
0
        return false;
464
0
    return true;
465
0
}
466
467
template <class TVal, class THasher>
468
TVal& RefHash3KeysIdPoolEnumerator<TVal, THasher>::nextElement()
469
0
{
470
    // If our index is zero or past the end, then we are done
471
0
    if (!fCurIndex || (fCurIndex > fToEnum->fIdCounter))
472
0
        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
473
474
    // Return the current element and bump the index
475
0
    return *fToEnum->fIdPtrs[fCurIndex++];
476
0
}
477
478
template <class TVal, class THasher>
479
void RefHash3KeysIdPoolEnumerator<TVal, THasher>::Reset()
480
0
{
481
    //
482
    //  Find the next available bucket element in the pool. We use the id
483
    //  array since its very easy to enumerator through by just maintaining
484
    //  an index. If the id counter is zero, then its empty and we leave the
485
    //  current index to zero.
486
    //
487
0
    fCurIndex = fToEnum->fIdCounter ? 1:0;
488
489
0
}
490
491
template <class TVal, class THasher>
492
XMLSize_t RefHash3KeysIdPoolEnumerator<TVal, THasher>::size() const
493
0
{
494
0
    return fToEnum->fIdCounter;
495
0
}
496
497
template <class TVal, class THasher>
498
void RefHash3KeysIdPoolEnumerator<TVal, THasher>::resetKey()
499
0
{
500
0
    fCurHash = (XMLSize_t)-1;
501
0
    fCurElem = 0;
502
0
    findNext();
503
0
}
504
505
template <class TVal, class THasher>
506
bool RefHash3KeysIdPoolEnumerator<TVal, THasher>::hasMoreKeys() const
507
0
{
508
    //
509
    //  If our current has is at the max and there are no more elements
510
    //  in the current bucket, then no more elements.
511
    //
512
0
    if (!fCurElem && (fCurHash == fToEnum->fHashModulus))
513
0
        return false;
514
515
0
    return true;
516
0
}
517
518
template <class TVal, class THasher>
519
void RefHash3KeysIdPoolEnumerator<TVal, THasher>::nextElementKey(void*& retKey1, int& retKey2, int& retKey3)
520
0
{
521
    // Make sure we have an element to return
522
0
    if (!hasMoreKeys())
523
0
        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
524
525
    //
526
    //  Save the current element, then move up to the next one for the
527
    //  next time around.
528
    //
529
0
    RefHash3KeysTableBucketElem<TVal>* saveElem = fCurElem;
530
0
    findNext();
531
532
0
    retKey1 = saveElem->fKey1;
533
0
    retKey2 = saveElem->fKey2;
534
0
    retKey3 = saveElem->fKey3;
535
536
0
    return;
537
0
}
538
539
template <class TVal, class THasher>
540
void RefHash3KeysIdPoolEnumerator<TVal, THasher>::findNext()
541
0
{
542
    //
543
    //  If there is a current element, move to its next element. If this
544
    //  hits the end of the bucket, the next block will handle the rest.
545
    //
546
0
    if (fCurElem)
547
0
        fCurElem = fCurElem->fNext;
548
549
    //
550
    //  If the current element is null, then we have to move up to the
551
    //  next hash value. If that is the hash modulus, then we cannot
552
    //  go further.
553
    //
554
0
    if (!fCurElem)
555
0
    {
556
0
        fCurHash++;
557
0
        if (fCurHash == fToEnum->fHashModulus)
558
0
            return;
559
560
        // Else find the next non-empty bucket
561
0
        while (fToEnum->fBucketList[fCurHash]==0)
562
0
        {
563
            // Bump to the next hash value. If we max out return
564
0
            fCurHash++;
565
0
            if (fCurHash == fToEnum->fHashModulus)
566
0
                return;
567
0
        }
568
0
        fCurElem = fToEnum->fBucketList[fCurHash];
569
0
    }
570
0
}
571
572
XERCES_CPP_NAMESPACE_END