• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)30 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)
31 
32 UVector::UVector(UErrorCode &status) :
33         UVector(nullptr, nullptr, DEFAULT_CAPACITY, status) {
34 }
35 
UVector(int32_t initialCapacity,UErrorCode & status)36 UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
37         UVector(nullptr, nullptr, initialCapacity, status) {
38 }
39 
UVector(UObjectDeleter * d,UElementsAreEqual * c,UErrorCode & status)40 UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, UErrorCode &status) :
41         UVector(d, c, DEFAULT_CAPACITY, status) {
42 }
43 
UVector(UObjectDeleter * d,UElementsAreEqual * c,int32_t initialCapacity,UErrorCode & status)44 UVector::UVector(UObjectDeleter *d, UElementsAreEqual *c, int32_t initialCapacity, UErrorCode &status) :
45     deleter(d),
46     comparer(c)
47 {
48     if (U_FAILURE(status)) {
49         return;
50     }
51     // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
52     if ((initialCapacity < 1) || (initialCapacity > (int32_t)(INT32_MAX / sizeof(UElement)))) {
53         initialCapacity = DEFAULT_CAPACITY;
54     }
55     elements = (UElement *)uprv_malloc(sizeof(UElement)*initialCapacity);
56     if (elements == nullptr) {
57         status = U_MEMORY_ALLOCATION_ERROR;
58     } else {
59         capacity = initialCapacity;
60     }
61 }
62 
~UVector()63 UVector::~UVector() {
64     removeAllElements();
65     uprv_free(elements);
66     elements = nullptr;
67 }
68 
69 /**
70  * Assign this object to another (make this a copy of 'other').
71  * Use the 'assign' function to assign each element.
72  */
assign(const UVector & other,UElementAssigner * assign,UErrorCode & ec)73 void UVector::assign(const UVector& other, UElementAssigner *assign, UErrorCode &ec) {
74     if (ensureCapacity(other.count, ec)) {
75         setSize(other.count, ec);
76         if (U_SUCCESS(ec)) {
77             for (int32_t i=0; i<other.count; ++i) {
78                 if (elements[i].pointer != nullptr && deleter != nullptr) {
79                     (*deleter)(elements[i].pointer);
80                 }
81                 (*assign)(&elements[i], &other.elements[i]);
82             }
83         }
84     }
85 }
86 
87 // This only does something sensible if this object has a non-null comparer
operator ==(const UVector & other) const88 bool UVector::operator==(const UVector& other) const {
89     U_ASSERT(comparer != nullptr);
90     if (count != other.count) return false;
91     if (comparer != nullptr) {
92         // Compare using this object's comparer
93         for (int32_t i=0; i<count; ++i) {
94             if (!(*comparer)(elements[i], other.elements[i])) {
95                 return false;
96             }
97         }
98     }
99     return true;
100 }
101 
addElement(void * obj,UErrorCode & status)102 void UVector::addElement(void* obj, UErrorCode &status) {
103     U_ASSERT(deleter == nullptr);
104     if (ensureCapacity(count + 1, status)) {
105         elements[count++].pointer = obj;
106     }
107 }
108 
adoptElement(void * obj,UErrorCode & status)109 void UVector::adoptElement(void* obj, UErrorCode &status) {
110     U_ASSERT(deleter != nullptr);
111     if (ensureCapacity(count + 1, status)) {
112         elements[count++].pointer = obj;
113     } else {
114         (*deleter)(obj);
115     }
116 }
addElement(int32_t elem,UErrorCode & status)117 void UVector::addElement(int32_t elem, UErrorCode &status) {
118     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
119     if (ensureCapacity(count + 1, status)) {
120         elements[count].pointer = nullptr;     // Pointers may be bigger than ints.
121         elements[count].integer = elem;
122         count++;
123     }
124 }
125 
setElementAt(void * obj,int32_t index)126 void UVector::setElementAt(void* obj, int32_t index) {
127     if (0 <= index && index < count) {
128         if (elements[index].pointer != nullptr && deleter != nullptr) {
129             (*deleter)(elements[index].pointer);
130         }
131         elements[index].pointer = obj;
132     } else {
133         /* index out of range */
134         if (deleter != nullptr) {
135             (*deleter)(obj);
136         }
137     }
138 }
139 
setElementAt(int32_t elem,int32_t index)140 void UVector::setElementAt(int32_t elem, int32_t index) {
141     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
142     if (0 <= index && index < count) {
143         elements[index].pointer = nullptr;
144         elements[index].integer = elem;
145     }
146     /* else index out of range */
147 }
148 
insertElementAt(void * obj,int32_t index,UErrorCode & status)149 void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) {
150     if (ensureCapacity(count + 1, status)) {
151         if (0 <= index && index <= count) {
152             for (int32_t i=count; i>index; --i) {
153                 elements[i] = elements[i-1];
154             }
155             elements[index].pointer = obj;
156             ++count;
157         } else {
158             /* index out of range */
159             status = U_ILLEGAL_ARGUMENT_ERROR;
160         }
161     }
162     if (U_FAILURE(status) && deleter != nullptr) {
163         (*deleter)(obj);
164     }
165 }
166 
insertElementAt(int32_t elem,int32_t index,UErrorCode & status)167 void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
168     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
169     // must have 0 <= index <= count
170     if (ensureCapacity(count + 1, status)) {
171         if (0 <= index && index <= count) {
172             for (int32_t i=count; i>index; --i) {
173                 elements[i] = elements[i-1];
174             }
175             elements[index].pointer = nullptr;
176             elements[index].integer = elem;
177             ++count;
178         } else {
179             /* index out of range */
180             status = U_ILLEGAL_ARGUMENT_ERROR;
181         }
182     }
183 }
184 
elementAt(int32_t index) const185 void* UVector::elementAt(int32_t index) const {
186     return (0 <= index && index < count) ? elements[index].pointer : 0;
187 }
188 
elementAti(int32_t index) const189 int32_t UVector::elementAti(int32_t index) const {
190     return (0 <= index && index < count) ? elements[index].integer : 0;
191 }
192 
containsAll(const UVector & other) const193 UBool UVector::containsAll(const UVector& other) const {
194     for (int32_t i=0; i<other.size(); ++i) {
195         if (indexOf(other.elements[i]) < 0) {
196             return false;
197         }
198     }
199     return true;
200 }
201 
containsNone(const UVector & other) const202 UBool UVector::containsNone(const UVector& other) const {
203     for (int32_t i=0; i<other.size(); ++i) {
204         if (indexOf(other.elements[i]) >= 0) {
205             return false;
206         }
207     }
208     return true;
209 }
210 
removeAll(const UVector & other)211 UBool UVector::removeAll(const UVector& other) {
212     UBool changed = false;
213     for (int32_t i=0; i<other.size(); ++i) {
214         int32_t j = indexOf(other.elements[i]);
215         if (j >= 0) {
216             removeElementAt(j);
217             changed = true;
218         }
219     }
220     return changed;
221 }
222 
retainAll(const UVector & other)223 UBool UVector::retainAll(const UVector& other) {
224     UBool changed = false;
225     for (int32_t j=size()-1; j>=0; --j) {
226         int32_t i = other.indexOf(elements[j]);
227         if (i < 0) {
228             removeElementAt(j);
229             changed = true;
230         }
231     }
232     return changed;
233 }
234 
removeElementAt(int32_t index)235 void UVector::removeElementAt(int32_t index) {
236     void* e = orphanElementAt(index);
237     if (e != nullptr && deleter != nullptr) {
238         (*deleter)(e);
239     }
240 }
241 
removeElement(void * obj)242 UBool UVector::removeElement(void* obj) {
243     int32_t i = indexOf(obj);
244     if (i >= 0) {
245         removeElementAt(i);
246         return true;
247     }
248     return false;
249 }
250 
removeAllElements(void)251 void UVector::removeAllElements(void) {
252     if (deleter != nullptr) {
253         for (int32_t i=0; i<count; ++i) {
254             if (elements[i].pointer != nullptr) {
255                 (*deleter)(elements[i].pointer);
256             }
257         }
258     }
259     count = 0;
260 }
261 
equals(const UVector & other) const262 UBool   UVector::equals(const UVector &other) const {
263     int      i;
264 
265     if (this->count != other.count) {
266         return false;
267     }
268     if (comparer == nullptr) {
269         for (i=0; i<count; i++) {
270             if (elements[i].pointer != other.elements[i].pointer) {
271                 return false;
272             }
273         }
274     } else {
275         UElement key;
276         for (i=0; i<count; i++) {
277             key.pointer = &other.elements[i];
278             if (!(*comparer)(key, elements[i])) {
279                 return false;
280             }
281         }
282     }
283     return true;
284 }
285 
286 
287 
indexOf(void * obj,int32_t startIndex) const288 int32_t UVector::indexOf(void* obj, int32_t startIndex) const {
289     UElement key;
290     key.pointer = obj;
291     return indexOf(key, startIndex, HINT_KEY_POINTER);
292 }
293 
indexOf(int32_t obj,int32_t startIndex) const294 int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const {
295     UElement key;
296     key.integer = obj;
297     return indexOf(key, startIndex, HINT_KEY_INTEGER);
298 }
299 
indexOf(UElement key,int32_t startIndex,int8_t hint) const300 int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
301     if (comparer != nullptr) {
302         for (int32_t i=startIndex; i<count; ++i) {
303             if ((*comparer)(key, elements[i])) {
304                 return i;
305             }
306         }
307     } else {
308         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             if (hint & HINT_KEY_POINTER) {
313                 if (key.pointer == elements[i].pointer) {
314                     return i;
315                 }
316             } else {
317                 if (key.integer == elements[i].integer) {
318                     return i;
319                 }
320             }
321         }
322     }
323     return -1;
324 }
325 
ensureCapacity(int32_t minimumCapacity,UErrorCode & status)326 UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
327     if (U_FAILURE(status)) {
328         return false;
329     }
330     if (minimumCapacity < 0) {
331         status = U_ILLEGAL_ARGUMENT_ERROR;
332         return false;
333     }
334     if (capacity < minimumCapacity) {
335         if (capacity > (INT32_MAX - 1) / 2) {        	// integer overflow check
336             status = U_ILLEGAL_ARGUMENT_ERROR;
337             return false;
338         }
339         int32_t newCap = capacity * 2;
340         if (newCap < minimumCapacity) {
341             newCap = minimumCapacity;
342         }
343         if (newCap > (int32_t)(INT32_MAX / sizeof(UElement))) {	// integer overflow check
344             // We keep the original memory contents on bad minimumCapacity.
345             status = U_ILLEGAL_ARGUMENT_ERROR;
346             return false;
347         }
348         UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap);
349         if (newElems == nullptr) {
350             // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
351             status = U_MEMORY_ALLOCATION_ERROR;
352             return false;
353         }
354         elements = newElems;
355         capacity = newCap;
356     }
357     return true;
358 }
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  */
setSize(int32_t newSize,UErrorCode & status)366 void UVector::setSize(int32_t newSize, UErrorCode &status) {
367     if (!ensureCapacity(newSize, status)) {
368         return;
369     }
370     if (newSize > count) {
371         UElement empty;
372         empty.pointer = nullptr;
373         empty.integer = 0;
374         for (int32_t i=count; i<newSize; ++i) {
375             elements[i] = empty;
376         }
377     } else {
378         /* Most efficient to count down */
379         for (int32_t i=count-1; i>=newSize; --i) {
380             removeElementAt(i);
381         }
382     }
383     count = newSize;
384 }
385 
386 /**
387  * Fill in the given array with all elements of this vector.
388  */
toArray(void ** result) const389 void** UVector::toArray(void** result) const {
390     void** a = result;
391     for (int i=0; i<count; ++i) {
392         *a++ = elements[i].pointer;
393     }
394     return result;
395 }
396 
setDeleter(UObjectDeleter * d)397 UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
398     UObjectDeleter *old = deleter;
399     deleter = d;
400     return old;
401 }
402 
setComparer(UElementsAreEqual * d)403 UElementsAreEqual *UVector::setComparer(UElementsAreEqual *d) {
404     UElementsAreEqual *old = comparer;
405     comparer = d;
406     return old;
407 }
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  */
orphanElementAt(int32_t index)418 void* UVector::orphanElementAt(int32_t index) {
419     void* e = nullptr;
420     if (0 <= index && index < count) {
421         e = elements[index].pointer;
422         for (int32_t i=index; i<count-1; ++i) {
423             elements[i] = elements[i+1];
424         }
425         --count;
426     }
427     /* else index out of range */
428     return e;
429 }
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  */
sortedInsert(void * obj,UElementComparator * compare,UErrorCode & ec)436 void UVector::sortedInsert(void* obj, UElementComparator *compare, UErrorCode& ec) {
437     UElement e;
438     e.pointer = obj;
439     sortedInsert(e, compare, ec);
440 }
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  */
sortedInsert(int32_t obj,UElementComparator * compare,UErrorCode & ec)447 void UVector::sortedInsert(int32_t obj, UElementComparator *compare, UErrorCode& ec) {
448     U_ASSERT(deleter == nullptr);
449     UElement e {};
450     e.integer = obj;
451     sortedInsert(e, compare, ec);
452 }
453 
454 // ASSUME elements[] IS CURRENTLY SORTED
sortedInsert(UElement e,UElementComparator * compare,UErrorCode & ec)455 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     if (!ensureCapacity(count + 1, ec)) {
462         if (deleter != nullptr) {
463             (*deleter)(e.pointer);
464         }
465         return;
466     }
467     int32_t min = 0, max = count;
468     while (min != max) {
469         int32_t probe = (min + max) / 2;
470         int32_t c = (*compare)(elements[probe], e);
471         if (c > 0) {
472             max = probe;
473         } else {
474             // assert(c <= 0);
475             min = probe + 1;
476         }
477     }
478     for (int32_t i=count; i>min; --i) {
479         elements[i] = elements[i-1];
480     }
481     elements[min] = e;
482     ++count;
483 }
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
sortComparator(const void * context,const void * left,const void * right)497 sortComparator(const void *context, const void *left, const void *right) {
498     UElementComparator *compare = *static_cast<UElementComparator * const *>(context);
499     UElement e1 = *static_cast<const UElement *>(left);
500     UElement e2 = *static_cast<const UElement *>(right);
501     int32_t result = (*compare)(e1, e2);
502     return result;
503 }
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
sortiComparator(const void *,const void * left,const void * right)511 sortiComparator(const void * /*context */, const void *left, const void *right) {
512     const UElement *e1 = static_cast<const UElement *>(left);
513     const UElement *e2 = static_cast<const UElement *>(right);
514     int32_t result = e1->integer < e2->integer? -1 :
515                      e1->integer == e2->integer? 0 : 1;
516     return result;
517 }
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   */
sorti(UErrorCode & ec)525 void UVector::sorti(UErrorCode &ec) {
526     if (U_SUCCESS(ec)) {
527         uprv_sortArray(elements, count, sizeof(UElement),
528                        sortiComparator, nullptr,  false, &ec);
529     }
530 }
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  */
sort(UElementComparator * compare,UErrorCode & ec)547 void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
548     if (U_SUCCESS(ec)) {
549         uprv_sortArray(elements, count, sizeof(UElement),
550                        sortComparator, &compare, false, &ec);
551     }
552 }
553 
554 
555 /**
556  *  Stable sort with a user supplied comparator of type UComparator.
557  */
sortWithUComparator(UComparator * compare,const void * context,UErrorCode & ec)558 void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
559     if (U_SUCCESS(ec)) {
560         uprv_sortArray(elements, count, sizeof(UElement),
561                        compare, context, true, &ec);
562     }
563 }
564 
565 U_NAMESPACE_END
566 
567