• 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 
102 // TODO: delete this function once all call sites have been migrated to the
103 //       new addElement().
addElementX(void * obj,UErrorCode & status)104 void UVector::addElementX(void* obj, UErrorCode &status) {
105     if (ensureCapacityX(count + 1, status)) {
106         elements[count++].pointer = obj;
107     }
108 }
109 
addElement(void * obj,UErrorCode & status)110 void UVector::addElement(void* obj, UErrorCode &status) {
111     U_ASSERT(deleter == nullptr);
112     if (ensureCapacity(count + 1, status)) {
113         elements[count++].pointer = obj;
114     }
115 }
116 
adoptElement(void * obj,UErrorCode & status)117 void UVector::adoptElement(void* obj, UErrorCode &status) {
118     U_ASSERT(deleter != nullptr);
119     if (ensureCapacity(count + 1, status)) {
120         elements[count++].pointer = obj;
121     } else {
122         (*deleter)(obj);
123     }
124 }
addElement(int32_t elem,UErrorCode & status)125 void UVector::addElement(int32_t elem, UErrorCode &status) {
126     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
127     if (ensureCapacity(count + 1, status)) {
128         elements[count].pointer = nullptr;     // Pointers may be bigger than ints.
129         elements[count].integer = elem;
130         count++;
131     }
132 }
133 
setElementAt(void * obj,int32_t index)134 void UVector::setElementAt(void* obj, int32_t index) {
135     if (0 <= index && index < count) {
136         if (elements[index].pointer != nullptr && deleter != nullptr) {
137             (*deleter)(elements[index].pointer);
138         }
139         elements[index].pointer = obj;
140     } else {
141         /* index out of range */
142         if (deleter != nullptr) {
143             (*deleter)(obj);
144         }
145     }
146 }
147 
setElementAt(int32_t elem,int32_t index)148 void UVector::setElementAt(int32_t elem, int32_t index) {
149     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
150     if (0 <= index && index < count) {
151         elements[index].pointer = nullptr;
152         elements[index].integer = elem;
153     }
154     /* else index out of range */
155 }
156 
insertElementAt(void * obj,int32_t index,UErrorCode & status)157 void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) {
158     if (ensureCapacity(count + 1, status)) {
159         if (0 <= index && index <= count) {
160             for (int32_t i=count; i>index; --i) {
161                 elements[i] = elements[i-1];
162             }
163             elements[index].pointer = obj;
164             ++count;
165         } else {
166             /* index out of range */
167             status = U_ILLEGAL_ARGUMENT_ERROR;
168         }
169     }
170     if (U_FAILURE(status) && deleter != nullptr) {
171         (*deleter)(obj);
172     }
173 }
174 
insertElementAt(int32_t elem,int32_t index,UErrorCode & status)175 void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
176     U_ASSERT(deleter == nullptr);  // Usage error. Mixing up ints and pointers.
177     // must have 0 <= index <= count
178     if (ensureCapacity(count + 1, status)) {
179         if (0 <= index && index <= count) {
180             for (int32_t i=count; i>index; --i) {
181                 elements[i] = elements[i-1];
182             }
183             elements[index].pointer = nullptr;
184             elements[index].integer = elem;
185             ++count;
186         } else {
187             /* index out of range */
188             status = U_ILLEGAL_ARGUMENT_ERROR;
189         }
190     }
191 }
192 
elementAt(int32_t index) const193 void* UVector::elementAt(int32_t index) const {
194     return (0 <= index && index < count) ? elements[index].pointer : 0;
195 }
196 
elementAti(int32_t index) const197 int32_t UVector::elementAti(int32_t index) const {
198     return (0 <= index && index < count) ? elements[index].integer : 0;
199 }
200 
containsAll(const UVector & other) const201 UBool UVector::containsAll(const UVector& other) const {
202     for (int32_t i=0; i<other.size(); ++i) {
203         if (indexOf(other.elements[i]) < 0) {
204             return FALSE;
205         }
206     }
207     return TRUE;
208 }
209 
containsNone(const UVector & other) const210 UBool UVector::containsNone(const UVector& other) const {
211     for (int32_t i=0; i<other.size(); ++i) {
212         if (indexOf(other.elements[i]) >= 0) {
213             return FALSE;
214         }
215     }
216     return TRUE;
217 }
218 
removeAll(const UVector & other)219 UBool UVector::removeAll(const UVector& other) {
220     UBool changed = FALSE;
221     for (int32_t i=0; i<other.size(); ++i) {
222         int32_t j = indexOf(other.elements[i]);
223         if (j >= 0) {
224             removeElementAt(j);
225             changed = TRUE;
226         }
227     }
228     return changed;
229 }
230 
retainAll(const UVector & other)231 UBool UVector::retainAll(const UVector& other) {
232     UBool changed = FALSE;
233     for (int32_t j=size()-1; j>=0; --j) {
234         int32_t i = other.indexOf(elements[j]);
235         if (i < 0) {
236             removeElementAt(j);
237             changed = TRUE;
238         }
239     }
240     return changed;
241 }
242 
removeElementAt(int32_t index)243 void UVector::removeElementAt(int32_t index) {
244     void* e = orphanElementAt(index);
245     if (e != nullptr && deleter != nullptr) {
246         (*deleter)(e);
247     }
248 }
249 
removeElement(void * obj)250 UBool UVector::removeElement(void* obj) {
251     int32_t i = indexOf(obj);
252     if (i >= 0) {
253         removeElementAt(i);
254         return TRUE;
255     }
256     return FALSE;
257 }
258 
removeAllElements(void)259 void UVector::removeAllElements(void) {
260     if (deleter != nullptr) {
261         for (int32_t i=0; i<count; ++i) {
262             if (elements[i].pointer != nullptr) {
263                 (*deleter)(elements[i].pointer);
264             }
265         }
266     }
267     count = 0;
268 }
269 
equals(const UVector & other) const270 UBool   UVector::equals(const UVector &other) const {
271     int      i;
272 
273     if (this->count != other.count) {
274         return FALSE;
275     }
276     if (comparer == nullptr) {
277         for (i=0; i<count; i++) {
278             if (elements[i].pointer != other.elements[i].pointer) {
279                 return FALSE;
280             }
281         }
282     } else {
283         UElement key;
284         for (i=0; i<count; i++) {
285             key.pointer = &other.elements[i];
286             if (!(*comparer)(key, elements[i])) {
287                 return FALSE;
288             }
289         }
290     }
291     return TRUE;
292 }
293 
294 
295 
indexOf(void * obj,int32_t startIndex) const296 int32_t UVector::indexOf(void* obj, int32_t startIndex) const {
297     UElement key;
298     key.pointer = obj;
299     return indexOf(key, startIndex, HINT_KEY_POINTER);
300 }
301 
indexOf(int32_t obj,int32_t startIndex) const302 int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const {
303     UElement key;
304     key.integer = obj;
305     return indexOf(key, startIndex, HINT_KEY_INTEGER);
306 }
307 
indexOf(UElement key,int32_t startIndex,int8_t hint) const308 int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
309     if (comparer != nullptr) {
310         for (int32_t i=startIndex; i<count; ++i) {
311             if ((*comparer)(key, elements[i])) {
312                 return i;
313             }
314         }
315     } else {
316         for (int32_t i=startIndex; i<count; ++i) {
317             /* Pointers are not always the same size as ints so to perform
318              * a valid comparison we need to know whether we are being
319              * provided an int or a pointer. */
320             if (hint & HINT_KEY_POINTER) {
321                 if (key.pointer == elements[i].pointer) {
322                     return i;
323                 }
324             } else {
325                 if (key.integer == elements[i].integer) {
326                     return i;
327                 }
328             }
329         }
330     }
331     return -1;
332 }
333 
ensureCapacityX(int32_t minimumCapacity,UErrorCode & status)334 UBool UVector::ensureCapacityX(int32_t minimumCapacity, UErrorCode &status) {
335     if (minimumCapacity < 0) {
336         status = U_ILLEGAL_ARGUMENT_ERROR;
337         return FALSE;
338 	}
339     if (capacity < minimumCapacity) {
340         if (capacity > (INT32_MAX - 1) / 2) {        	// integer overflow check
341         	status = U_ILLEGAL_ARGUMENT_ERROR;
342         	return FALSE;
343         }
344         int32_t newCap = capacity * 2;
345         if (newCap < minimumCapacity) {
346             newCap = minimumCapacity;
347         }
348         if (newCap > (int32_t)(INT32_MAX / sizeof(UElement))) {	// integer overflow check
349         	// We keep the original memory contents on bad minimumCapacity.
350         	status = U_ILLEGAL_ARGUMENT_ERROR;
351         	return FALSE;
352         }
353         UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap);
354         if (newElems == nullptr) {
355             // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
356             status = U_MEMORY_ALLOCATION_ERROR;
357             return FALSE;
358         }
359         elements = newElems;
360         capacity = newCap;
361     }
362     return TRUE;
363 }
364 
365 
ensureCapacity(int32_t minimumCapacity,UErrorCode & status)366 UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
367     if (U_FAILURE(status)) {
368         return false;
369     }
370     if (minimumCapacity < 0) {
371         status = U_ILLEGAL_ARGUMENT_ERROR;
372         return false;
373 	}
374     if (capacity < minimumCapacity) {
375         if (capacity > (INT32_MAX - 1) / 2) {        	// integer overflow check
376             status = U_ILLEGAL_ARGUMENT_ERROR;
377             return false;
378         }
379         int32_t newCap = capacity * 2;
380         if (newCap < minimumCapacity) {
381             newCap = minimumCapacity;
382         }
383         if (newCap > (int32_t)(INT32_MAX / sizeof(UElement))) {	// integer overflow check
384             // We keep the original memory contents on bad minimumCapacity.
385             status = U_ILLEGAL_ARGUMENT_ERROR;
386             return false;
387         }
388         UElement* newElems = (UElement *)uprv_realloc(elements, sizeof(UElement)*newCap);
389         if (newElems == nullptr) {
390             // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
391             status = U_MEMORY_ALLOCATION_ERROR;
392             return false;
393         }
394         elements = newElems;
395         capacity = newCap;
396     }
397     return true;
398 }
399 /**
400  * Change the size of this vector as follows: If newSize is smaller,
401  * then truncate the array, possibly deleting held elements for i >=
402  * newSize.  If newSize is larger, grow the array, filling in new
403  * slots with nullptr.
404  */
setSize(int32_t newSize,UErrorCode & status)405 void UVector::setSize(int32_t newSize, UErrorCode &status) {
406     if (!ensureCapacity(newSize, status)) {
407         return;
408     }
409     if (newSize > count) {
410         UElement empty;
411         empty.pointer = nullptr;
412         empty.integer = 0;
413         for (int32_t i=count; i<newSize; ++i) {
414             elements[i] = empty;
415         }
416     } else {
417         /* Most efficient to count down */
418         for (int32_t i=count-1; i>=newSize; --i) {
419             removeElementAt(i);
420         }
421     }
422     count = newSize;
423 }
424 
425 /**
426  * Fill in the given array with all elements of this vector.
427  */
toArray(void ** result) const428 void** UVector::toArray(void** result) const {
429     void** a = result;
430     for (int i=0; i<count; ++i) {
431         *a++ = elements[i].pointer;
432     }
433     return result;
434 }
435 
setDeleter(UObjectDeleter * d)436 UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
437     UObjectDeleter *old = deleter;
438     deleter = d;
439     return old;
440 }
441 
setComparer(UElementsAreEqual * d)442 UElementsAreEqual *UVector::setComparer(UElementsAreEqual *d) {
443     UElementsAreEqual *old = comparer;
444     comparer = d;
445     return old;
446 }
447 
448 /**
449  * Removes the element at the given index from this vector and
450  * transfer ownership of it to the caller.  After this call, the
451  * caller owns the result and must delete it and the vector entry
452  * at 'index' is removed, shifting all subsequent entries back by
453  * one index and shortening the size of the vector by one.  If the
454  * index is out of range or if there is no item at the given index
455  * then 0 is returned and the vector is unchanged.
456  */
orphanElementAt(int32_t index)457 void* UVector::orphanElementAt(int32_t index) {
458     void* e = nullptr;
459     if (0 <= index && index < count) {
460         e = elements[index].pointer;
461         for (int32_t i=index; i<count-1; ++i) {
462             elements[i] = elements[i+1];
463         }
464         --count;
465     }
466     /* else index out of range */
467     return e;
468 }
469 
470 /**
471  * Insert the given object into this vector at its sorted position
472  * as defined by 'compare'.  The current elements are assumed to
473  * be sorted already.
474  */
sortedInsert(void * obj,UElementComparator * compare,UErrorCode & ec)475 void UVector::sortedInsert(void* obj, UElementComparator *compare, UErrorCode& ec) {
476     UElement e;
477     e.pointer = obj;
478     sortedInsert(e, compare, ec);
479 }
480 
481 /**
482  * Insert the given integer into this vector at its sorted position
483  * as defined by 'compare'.  The current elements are assumed to
484  * be sorted already.
485  */
sortedInsert(int32_t obj,UElementComparator * compare,UErrorCode & ec)486 void UVector::sortedInsert(int32_t obj, UElementComparator *compare, UErrorCode& ec) {
487     U_ASSERT(deleter == nullptr);
488     UElement e {};
489     e.integer = obj;
490     sortedInsert(e, compare, ec);
491 }
492 
493 // ASSUME elements[] IS CURRENTLY SORTED
sortedInsert(UElement e,UElementComparator * compare,UErrorCode & ec)494 void UVector::sortedInsert(UElement e, UElementComparator *compare, UErrorCode& ec) {
495     // Perform a binary search for the location to insert tok at.  Tok
496     // will be inserted between two elements a and b such that a <=
497     // tok && tok < b, where there is a 'virtual' elements[-1] always
498     // less than tok and a 'virtual' elements[count] always greater
499     // than tok.
500     if (!ensureCapacity(count + 1, ec)) {
501         if (deleter != nullptr) {
502             (*deleter)(e.pointer);
503         }
504         return;
505     }
506     int32_t min = 0, max = count;
507     while (min != max) {
508         int32_t probe = (min + max) / 2;
509         int32_t c = (*compare)(elements[probe], e);
510         if (c > 0) {
511             max = probe;
512         } else {
513             // assert(c <= 0);
514             min = probe + 1;
515         }
516     }
517     for (int32_t i=count; i>min; --i) {
518         elements[i] = elements[i-1];
519     }
520     elements[min] = e;
521     ++count;
522 }
523 
524 /**
525   *  Array sort comparator function.
526   *  Used from UVector::sort()
527   *  Conforms to function signature required for uprv_sortArray().
528   *  This function is essentially just a wrapper, to make a
529   *  UVector style comparator function usable with uprv_sortArray().
530   *
531   *  The context pointer to this function is a pointer back
532   *  (with some extra indirection) to the user supplied comparator.
533   *
534   */
535 static int32_t U_CALLCONV
sortComparator(const void * context,const void * left,const void * right)536 sortComparator(const void *context, const void *left, const void *right) {
537     UElementComparator *compare = *static_cast<UElementComparator * const *>(context);
538     UElement e1 = *static_cast<const UElement *>(left);
539     UElement e2 = *static_cast<const UElement *>(right);
540     int32_t result = (*compare)(e1, e2);
541     return result;
542 }
543 
544 
545 /**
546   *  Array sort comparison function for use from UVector::sorti()
547   *  Compares int32_t vector elements.
548   */
549 static int32_t U_CALLCONV
sortiComparator(const void *,const void * left,const void * right)550 sortiComparator(const void * /*context */, const void *left, const void *right) {
551     const UElement *e1 = static_cast<const UElement *>(left);
552     const UElement *e2 = static_cast<const UElement *>(right);
553     int32_t result = e1->integer < e2->integer? -1 :
554                      e1->integer == e2->integer? 0 : 1;
555     return result;
556 }
557 
558 /**
559   * Sort the vector, assuming it contains ints.
560   *     (A more general sort would take a comparison function, but it's
561   *     not clear whether UVector's UElementComparator or
562   *     UComparator from uprv_sortAray would be more appropriate.)
563   */
sorti(UErrorCode & ec)564 void UVector::sorti(UErrorCode &ec) {
565     if (U_SUCCESS(ec)) {
566         uprv_sortArray(elements, count, sizeof(UElement),
567                        sortiComparator, nullptr,  FALSE, &ec);
568     }
569 }
570 
571 
572 /**
573  *  Sort with a user supplied comparator.
574  *
575  *    The comparator function handling is confusing because the function type
576  *    for UVector  (as defined for sortedInsert()) is different from the signature
577  *    required by uprv_sortArray().  This is handled by passing the
578  *    the UVector sort function pointer via the context pointer to a
579  *    sortArray() comparator function, which can then call back to
580  *    the original user function.
581  *
582  *    An additional twist is that it's not safe to pass a pointer-to-function
583  *    as  a (void *) data pointer, so instead we pass a (data) pointer to a
584  *    pointer-to-function variable.
585  */
sort(UElementComparator * compare,UErrorCode & ec)586 void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
587     if (U_SUCCESS(ec)) {
588         uprv_sortArray(elements, count, sizeof(UElement),
589                        sortComparator, &compare, FALSE, &ec);
590     }
591 }
592 
593 
594 /**
595  *  Stable sort with a user supplied comparator of type UComparator.
596  */
sortWithUComparator(UComparator * compare,const void * context,UErrorCode & ec)597 void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
598     if (U_SUCCESS(ec)) {
599         uprv_sortArray(elements, count, sizeof(UElement),
600                        compare, context, TRUE, &ec);
601     }
602 }
603 
604 U_NAMESPACE_END
605 
606