Coverage Report

Created: 2026-08-14 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/common/uvector.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
******************************************************************************
5
* Copyright (C) 1999-2013, International Business Machines Corporation and
6
* others. All Rights Reserved.
7
******************************************************************************
8
*   Date        Name        Description
9
*   10/22/99    alan        Creation.
10
**********************************************************************
11
*/
12
13
#include "uvector.h"
14
#include "cmemory.h"
15
#include "uarrsort.h"
16
#include "uelement.h"
17
18
U_NAMESPACE_BEGIN
19
20
constexpr int32_t DEFAULT_CAPACITY = 8;
21
22
/*
23
 * Constants for hinting whether a key is an integer
24
 * or a pointer.  If a hint bit is zero, then the associated
25
 * token is assumed to be an integer. This is needed for iSeries
26
 */
27
constexpr int8_t HINT_KEY_POINTER = 1;
28
constexpr int8_t HINT_KEY_INTEGER = 0;
29
 
30
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)
31
32
UVector::UVector(UErrorCode &status) :
33
283k
        UVector(nullptr, nullptr, DEFAULT_CAPACITY, status) {
34
283k
}
35
36
UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
37
0
        UVector(nullptr, nullptr, initialCapacity, status) {
38
0
}
39
40
UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, UErrorCode &status) :
41
166k
        UVector(d, c, DEFAULT_CAPACITY, status) {
42
166k
}
43
44
UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, int32_t initialCapacity, UErrorCode &status) :
45
696k
    deleter(d),
46
696k
    comparer(c)
47
696k
{
48
696k
    if (U_FAILURE(status)) {
49
0
        return;
50
0
    }
51
    // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
52
696k
    if ((initialCapacity < 1) || (initialCapacity > static_cast<int32_t>(INT32_MAX / sizeof(UElement)))) {
53
0
        initialCapacity = DEFAULT_CAPACITY;
54
0
    }
55
696k
    elements = static_cast<UElement*>(uprv_malloc(sizeof(UElement) * initialCapacity));
56
696k
    if (elements == nullptr) {
57
0
        status = U_MEMORY_ALLOCATION_ERROR;
58
696k
    } else {
59
696k
        capacity = initialCapacity;
60
696k
    }
61
696k
}
62
63
695k
UVector::~UVector() {
64
695k
    removeAllElements();
65
695k
    uprv_free(elements);
66
695k
    elements = nullptr;
67
695k
}
68
69
/**
70
 * Assign this object to another (make this a copy of 'other').
71
 * Use the 'assign' function to assign each element.
72
 */
73
105k
void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode &ec) {
74
105k
    if (ensureCapacity(other.count, ec)) {
75
105k
        setSize(other.count, ec);
76
105k
        if (U_SUCCESS(ec)) {
77
4.84M
            for (int32_t i=0; i<other.count; ++i) {
78
4.74M
                if (elements[i].pointer != nullptr && deleter != nullptr) {
79
680k
                    (*deleter)(elements[i].pointer);
80
680k
                }
81
4.74M
                (*assign)(&elements[i], &other.elements[i]);
82
4.74M
            }
83
105k
        }
84
105k
    }
85
105k
}
86
87
// This only does something sensible if this object has a non-null comparer
88
0
bool UVector::operator==(const UVector& other) const {
89
0
    U_ASSERT(comparer != nullptr);
90
0
    if (count != other.count) return false;
91
0
    if (comparer != nullptr) {
92
        // Compare using this object's comparer
93
0
        for (int32_t i=0; i<count; ++i) {
94
0
            if (!(*comparer)(elements[i], other.elements[i])) {
95
0
                return false;
96
0
            }
97
0
        }
98
0
    }
99
0
    return true;
100
0
}
101
102
487k
void UVector::addElement(void* obj, UErrorCode &status) {
103
487k
    U_ASSERT(deleter == nullptr);
104
487k
    if (ensureCapacity(count + 1, status)) {
105
487k
        elements[count++].pointer = obj;
106
487k
    }
107
487k
}
108
109
15.9M
void UVector::adoptElement(void* obj, UErrorCode &status) {
110
15.9M
    U_ASSERT(deleter != nullptr);
111
15.9M
    if (ensureCapacity(count + 1, status)) {
112
15.9M
        elements[count++].pointer = obj;
113
15.9M
    } else {
114
0
        (*deleter)(obj);
115
0
    }
116
15.9M
}
117
1.11M
void UVector::addElement(int32_t elem, UErrorCode &status) {
118
1.11M
    U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
119
1.11M
    if (ensureCapacity(count + 1, status)) {
120
1.11M
        elements[count].pointer = nullptr;     // Pointers may be bigger than ints.
121
1.11M
        elements[count].integer = elem;
122
1.11M
        count++;
123
1.11M
    }
124
1.11M
}
125
126
0
void UVector::setElementAt(void* obj, int32_t index) {
127
0
    if (0 <= index && index < count) {
128
0
        if (elements[index].pointer != nullptr && deleter != nullptr) {
129
0
            (*deleter)(elements[index].pointer);
130
0
        }
131
0
        elements[index].pointer = obj;
132
0
    } else {
133
        /* index out of range */
134
0
        if (deleter != nullptr) {
135
0
            (*deleter)(obj);
136
0
        }
137
0
    }
138
0
}
139
140
0
void UVector::setElementAt(int32_t elem, int32_t index) {
141
0
    U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
142
0
    if (0 <= index && index < count) {
143
0
        elements[index].pointer = nullptr;
144
0
        elements[index].integer = elem;
145
0
    }
146
    /* else index out of range */
147
0
}
148
149
10.4M
void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) {
150
10.4M
    if (ensureCapacity(count + 1, status)) {
151
10.4M
        if (0 <= index && index <= count) {
152
10.4M
            for (int32_t i=count; i>index; --i) {
153
1.99k
                elements[i] = elements[i-1];
154
1.99k
            }
155
10.4M
            elements[index].pointer = obj;
156
10.4M
            ++count;
157
10.4M
        } else {
158
            /* index out of range */
159
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
160
0
        }
161
10.4M
    }
162
10.4M
    if (U_FAILURE(status) && deleter != nullptr) {
163
0
        (*deleter)(obj);
164
0
    }
165
10.4M
}
166
167
0
void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
168
0
    U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
169
    // must have 0 <= index <= count
170
0
    if (ensureCapacity(count + 1, status)) {
171
0
        if (0 <= index && index <= count) {
172
0
            for (int32_t i=count; i>index; --i) {
173
0
                elements[i] = elements[i-1];
174
0
            }
175
0
            elements[index].pointer = nullptr;
176
0
            elements[index].integer = elem;
177
0
            ++count;
178
0
        } else {
179
            /* index out of range */
180
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
181
0
        }
182
0
    }
183
0
}
184
185
110M
void* UVector::elementAt(int32_t index) const {
186
110M
    return (0 <= index && index < count) ? elements[index].pointer : nullptr;
187
110M
}
188
189
17.9M
int32_t UVector::elementAti(int32_t index) const {
190
17.9M
    return (0 <= index && index < count) ? elements[index].integer : 0;
191
17.9M
}
192
193
0
UBool UVector::containsAll(const UVector& other) const {
194
0
    for (int32_t i=0; i<other.size(); ++i) {
195
0
        if (indexOf(other.elements[i]) < 0) {
196
0
            return false;
197
0
        }
198
0
    }
199
0
    return true;
200
0
}
201
202
0
UBool UVector::containsNone(const UVector& other) const {
203
0
    for (int32_t i=0; i<other.size(); ++i) {
204
0
        if (indexOf(other.elements[i]) >= 0) {
205
0
            return false;
206
0
        }
207
0
    }
208
0
    return true;
209
0
}
210
211
7.71k
UBool UVector::removeAll(const UVector& other) {
212
7.71k
    UBool changed = false;
213
30.2k
    for (int32_t i=0; i<other.size(); ++i) {
214
22.5k
        int32_t j = indexOf(other.elements[i]);
215
22.5k
        if (j >= 0) {
216
10.9k
            removeElementAt(j);
217
10.9k
            changed = true;
218
10.9k
        }
219
22.5k
    }
220
7.71k
    return changed;
221
7.71k
}
222
223
1.08k
UBool UVector::retainAll(const UVector& other) {
224
1.08k
    UBool changed = false;
225
18.4k
    for (int32_t j=size()-1; j>=0; --j) {
226
17.4k
        int32_t i = other.indexOf(elements[j]);
227
17.4k
        if (i < 0) {
228
15.2k
            removeElementAt(j);
229
15.2k
            changed = true;
230
15.2k
        }
231
17.4k
    }
232
1.08k
    return changed;
233
1.08k
}
234
235
1.21M
void UVector::removeElementAt(int32_t index) {
236
1.21M
    void* e = orphanElementAt(index);
237
1.21M
    if (e != nullptr && deleter != nullptr) {
238
157k
        (*deleter)(e);
239
157k
    }
240
1.21M
}
241
242
0
UBool UVector::removeElement(void* obj) {
243
0
    int32_t i = indexOf(obj);
244
0
    if (i >= 0) {
245
0
        removeElementAt(i);
246
0
        return true;
247
0
    }
248
0
    return false;
249
0
}
250
251
779k
void UVector::removeAllElements() {
252
779k
    if (deleter != nullptr) {
253
24.9M
        for (int32_t i=0; i<count; ++i) {
254
24.3M
            if (elements[i].pointer != nullptr) {
255
24.3M
                (*deleter)(elements[i].pointer);
256
24.3M
            }
257
24.3M
        }
258
636k
    }
259
779k
    count = 0;
260
779k
}
261
262
0
UBool   UVector::equals(const UVector &other) const {
263
0
    int      i;
264
265
0
    if (this->count != other.count) {
266
0
        return false;
267
0
    }
268
0
    if (comparer == nullptr) {
269
0
        for (i=0; i<count; i++) {
270
0
            if (elements[i].pointer != other.elements[i].pointer) {
271
0
                return false;
272
0
            }
273
0
        }
274
0
    } else {
275
0
        UElement key;
276
0
        for (i=0; i<count; i++) {
277
0
            key.pointer = &other.elements[i];
278
0
            if (!(*comparer)(key, elements[i])) {
279
0
                return false;
280
0
            }
281
0
        }
282
0
    }
283
0
    return true;
284
0
}
285
286
287
288
8.86M
int32_t UVector::indexOf(void* obj, int32_t startIndex) const {
289
8.86M
    UElement key;
290
8.86M
    key.pointer = obj;
291
8.86M
    return indexOf(key, startIndex, HINT_KEY_POINTER);
292
8.86M
}
293
294
0
int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const {
295
0
    UElement key;
296
0
    key.integer = obj;
297
0
    return indexOf(key, startIndex, HINT_KEY_INTEGER);
298
0
}
299
300
8.90M
int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
301
8.90M
    if (comparer != nullptr) {
302
298M
        for (int32_t i=startIndex; i<count; ++i) {
303
293M
            if ((*comparer)(key, elements[i])) {
304
3.87M
                return i;
305
3.87M
            }
306
293M
        }
307
8.90M
    } else {
308
0
        for (int32_t i=startIndex; i<count; ++i) {
309
            /* Pointers are not always the same size as ints so to perform
310
             * a valid comparison we need to know whether we are being
311
             * provided an int or a pointer. */
312
0
            if (hint & HINT_KEY_POINTER) {
313
0
                if (key.pointer == elements[i].pointer) {
314
0
                    return i;
315
0
                }
316
0
            } else {
317
0
                if (key.integer == elements[i].integer) {
318
0
                    return i;
319
0
                }
320
0
            }
321
0
        }
322
0
    }
323
5.02M
    return -1;
324
8.90M
}
325
326
33.1M
UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
327
33.1M
    if (U_FAILURE(status)) {
328
3
        return false;
329
3
    }
330
33.1M
    if (minimumCapacity < 0) {
331
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
332
0
        return false;
333
0
    }
334
33.1M
    if (capacity < minimumCapacity) {
335
601k
        if (capacity > (INT32_MAX - 1) / 2) {         // integer overflow check
336
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
337
0
            return false;
338
0
        }
339
601k
        int32_t newCap = capacity * 2;
340
601k
        if (newCap < minimumCapacity) {
341
75.6k
            newCap = minimumCapacity;
342
75.6k
        }
343
601k
        if (newCap > static_cast<int32_t>(INT32_MAX / sizeof(UElement))) { // integer overflow check
344
            // We keep the original memory contents on bad minimumCapacity.
345
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
346
0
            return false;
347
0
        }
348
601k
        UElement* newElems = static_cast<UElement*>(uprv_realloc(elements, sizeof(UElement) * newCap));
349
601k
        if (newElems == nullptr) {
350
            // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
351
0
            status = U_MEMORY_ALLOCATION_ERROR;
352
0
            return false;
353
0
        }
354
601k
        elements = newElems;
355
601k
        capacity = newCap;
356
601k
    }
357
33.1M
    return true;
358
33.1M
}
359
360
/**
361
 * Change the size of this vector as follows: If newSize is smaller,
362
 * then truncate the array, possibly deleting held elements for i >=
363
 * newSize.  If newSize is larger, grow the array, filling in new
364
 * slots with nullptr.
365
 */
366
105k
void UVector::setSize(int32_t newSize, UErrorCode &status) {
367
105k
    if (!ensureCapacity(newSize, status)) {
368
0
        return;
369
0
    }
370
105k
    if (newSize > count) {
371
89.2k
        UElement empty;
372
89.2k
        empty.pointer = nullptr;
373
89.2k
        empty.integer = 0;
374
4.15M
        for (int32_t i=count; i<newSize; ++i) {
375
4.06M
            elements[i] = empty;
376
4.06M
        }
377
89.2k
    } else {
378
        /* Most efficient to count down */
379
17.4k
        for (int32_t i=count-1; i>=newSize; --i) {
380
1.65k
            removeElementAt(i);
381
1.65k
        }
382
15.7k
    }
383
105k
    count = newSize;
384
105k
}
385
386
/**
387
 * Fill in the given array with all elements of this vector.
388
 */
389
0
void** UVector::toArray(void** result) const {
390
0
    void** a = result;
391
0
    for (int i=0; i<count; ++i) {
392
0
        *a++ = elements[i].pointer;
393
0
    }
394
0
    return result;
395
0
}
396
397
221k
UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
398
221k
    UObjectDeleter *old = deleter;
399
221k
    deleter = d;
400
221k
    return old;
401
221k
}
402
403
166k
UElementsAreEqual *UVector::setComparer(UElementsAreEqual *d) {
404
166k
    UElementsAreEqual *old = comparer;
405
166k
    comparer = d;
406
166k
    return old;
407
166k
}
408
409
/**
410
 * Removes the element at the given index from this vector and
411
 * transfer ownership of it to the caller.  After this call, the
412
 * caller owns the result and must delete it and the vector entry
413
 * at 'index' is removed, shifting all subsequent entries back by
414
 * one index and shortening the size of the vector by one.  If the
415
 * index is out of range or if there is no item at the given index
416
 * then 0 is returned and the vector is unchanged.
417
 */
418
1.74M
void* UVector::orphanElementAt(int32_t index) {
419
1.74M
    void* e = nullptr;
420
1.74M
    if (0 <= index && index < count) {
421
1.74M
        e = elements[index].pointer;
422
3.36M
        for (int32_t i=index; i<count-1; ++i) {
423
1.62M
            elements[i] = elements[i+1];
424
1.62M
        }
425
1.74M
        --count;
426
1.74M
    }
427
    /* else index out of range */
428
1.74M
    return e;
429
1.74M
}
430
431
/**
432
 * Insert the given object into this vector at its sorted position
433
 * as defined by 'compare'.  The current elements are assumed to
434
 * be sorted already.
435
 */
436
5.04M
void UVector::sortedInsert(void* obj, UElementComparator *compare, UErrorCode& ec) {
437
5.04M
    UElement e;
438
5.04M
    e.pointer = obj;
439
5.04M
    sortedInsert(e, compare, ec);
440
5.04M
}
441
442
/**
443
 * Insert the given integer into this vector at its sorted position
444
 * as defined by 'compare'.  The current elements are assumed to
445
 * be sorted already.
446
 */
447
0
void UVector::sortedInsert(int32_t obj, UElementComparator *compare, UErrorCode& ec) {
448
0
    U_ASSERT(deleter == nullptr);
449
0
    UElement e {};
450
0
    e.integer = obj;
451
0
    sortedInsert(e, compare, ec);
452
0
}
453
454
// ASSUME elements[] IS CURRENTLY SORTED
455
5.04M
void UVector::sortedInsert(UElement e, UElementComparator *compare, UErrorCode& ec) {
456
    // Perform a binary search for the location to insert tok at.  Tok
457
    // will be inserted between two elements a and b such that a <=
458
    // tok && tok < b, where there is a 'virtual' elements[-1] always
459
    // less than tok and a 'virtual' elements[count] always greater
460
    // than tok.
461
5.04M
    if (!ensureCapacity(count + 1, ec)) {
462
0
        if (deleter != nullptr) {
463
0
            (*deleter)(e.pointer);
464
0
        }
465
0
        return;
466
0
    }
467
5.04M
    int32_t min = 0, max = count;
468
26.9M
    while (min != max) {
469
21.8M
        int32_t probe = (min + max) / 2;
470
21.8M
        int32_t c = (*compare)(elements[probe], e);
471
21.8M
        if (c > 0) {
472
6.83M
            max = probe;
473
15.0M
        } else {
474
            // assert(c <= 0);
475
15.0M
            min = probe + 1;
476
15.0M
        }
477
21.8M
    }
478
67.4M
    for (int32_t i=count; i>min; --i) {
479
62.4M
        elements[i] = elements[i-1];
480
62.4M
    }
481
5.04M
    elements[min] = e;
482
5.04M
    ++count;
483
5.04M
}
484
485
/**
486
  *  Array sort comparator function.
487
  *  Used from UVector::sort()
488
  *  Conforms to function signature required for uprv_sortArray().
489
  *  This function is essentially just a wrapper, to make a
490
  *  UVector style comparator function usable with uprv_sortArray().
491
  *
492
  *  The context pointer to this function is a pointer back
493
  *  (with some extra indirection) to the user supplied comparator.
494
  *  
495
  */
496
static int32_t U_CALLCONV
497
174M
sortComparator(const void *context, const void *left, const void *right) {
498
174M
    UElementComparator *compare = *static_cast<UElementComparator * const *>(context);
499
174M
    UElement e1 = *static_cast<const UElement *>(left);
500
174M
    UElement e2 = *static_cast<const UElement *>(right);
501
174M
    int32_t result = (*compare)(e1, e2);
502
174M
    return result;
503
174M
}
504
505
506
/**
507
  *  Array sort comparison function for use from UVector::sorti()
508
  *  Compares int32_t vector elements.
509
  */
510
static int32_t U_CALLCONV
511
0
sortiComparator(const void * /*context */, const void *left, const void *right) {
512
0
    const UElement *e1 = static_cast<const UElement *>(left);
513
0
    const UElement *e2 = static_cast<const UElement *>(right);
514
0
    int32_t result = e1->integer < e2->integer? -1 :
515
0
                     e1->integer == e2->integer? 0 : 1;
516
0
    return result;
517
0
}
518
519
/**
520
  * Sort the vector, assuming it contains ints.
521
  *     (A more general sort would take a comparison function, but it's
522
  *     not clear whether UVector's UElementComparator or
523
  *     UComparator from uprv_sortAray would be more appropriate.)
524
  */
525
0
void UVector::sorti(UErrorCode &ec) {
526
0
    if (U_SUCCESS(ec)) {
527
0
        uprv_sortArray(elements, count, sizeof(UElement),
528
0
                       sortiComparator, nullptr,  false, &ec);
529
0
    }
530
0
}
531
532
533
/**
534
 *  Sort with a user supplied comparator.
535
 *
536
 *    The comparator function handling is confusing because the function type
537
 *    for UVector  (as defined for sortedInsert()) is different from the signature
538
 *    required by uprv_sortArray().  This is handled by passing the
539
 *    the UVector sort function pointer via the context pointer to a
540
 *    sortArray() comparator function, which can then call back to
541
 *    the original user function.
542
 *
543
 *    An additional twist is that it's not safe to pass a pointer-to-function
544
 *    as  a (void *) data pointer, so instead we pass a (data) pointer to a
545
 *    pointer-to-function variable.
546
 */
547
12.7k
void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
548
12.7k
    if (U_SUCCESS(ec)) {
549
12.7k
        uprv_sortArray(elements, count, sizeof(UElement),
550
12.7k
                       sortComparator, &compare, false, &ec);
551
12.7k
    }
552
12.7k
}
553
554
555
/**
556
 *  Stable sort with a user supplied comparator of type UComparator.
557
 */
558
0
void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
559
0
    if (U_SUCCESS(ec)) {
560
0
        uprv_sortArray(elements, count, sizeof(UElement),
561
0
                       compare, context, true, &ec);
562
0
    }
563
0
}
564
565
U_NAMESPACE_END
566