1 /*
2 ******************************************************************************
3 * Copyright (C) 1999-2011, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
6 * Date Name Description
7 * 10/22/99 alan Creation.
8 **********************************************************************
9 */
10
11 #include "uvector.h"
12 #include "cmemory.h"
13 #include "uarrsort.h"
14
15 U_NAMESPACE_BEGIN
16
17 #define DEFAULT_CAPACITY 8
18
19 /*
20 * Constants for hinting whether a key is an integer
21 * or a pointer. If a hint bit is zero, then the associated
22 * token is assumed to be an integer. This is needed for iSeries
23 */
24 #define HINT_KEY_POINTER (1)
25 #define HINT_KEY_INTEGER (0)
26
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)27 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)
28
29 UVector::UVector(UErrorCode &status) :
30 count(0),
31 capacity(0),
32 elements(0),
33 deleter(0),
34 comparer(0)
35 {
36 _init(DEFAULT_CAPACITY, status);
37 }
38
UVector(int32_t initialCapacity,UErrorCode & status)39 UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
40 count(0),
41 capacity(0),
42 elements(0),
43 deleter(0),
44 comparer(0)
45 {
46 _init(initialCapacity, status);
47 }
48
UVector(UObjectDeleter * d,UKeyComparator * c,UErrorCode & status)49 UVector::UVector(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
50 count(0),
51 capacity(0),
52 elements(0),
53 deleter(d),
54 comparer(c)
55 {
56 _init(DEFAULT_CAPACITY, status);
57 }
58
UVector(UObjectDeleter * d,UKeyComparator * c,int32_t initialCapacity,UErrorCode & status)59 UVector::UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
60 count(0),
61 capacity(0),
62 elements(0),
63 deleter(d),
64 comparer(c)
65 {
66 _init(initialCapacity, status);
67 }
68
_init(int32_t initialCapacity,UErrorCode & status)69 void UVector::_init(int32_t initialCapacity, UErrorCode &status) {
70 if (U_FAILURE(status)) {
71 return;
72 }
73 // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
74 if ((initialCapacity < 1) || (initialCapacity > (int32_t)(INT32_MAX / sizeof(UHashTok)))) {
75 initialCapacity = DEFAULT_CAPACITY;
76 }
77 elements = (UHashTok *)uprv_malloc(sizeof(UHashTok)*initialCapacity);
78 if (elements == 0) {
79 status = U_MEMORY_ALLOCATION_ERROR;
80 } else {
81 capacity = initialCapacity;
82 }
83 }
84
~UVector()85 UVector::~UVector() {
86 removeAllElements();
87 uprv_free(elements);
88 elements = 0;
89 }
90
91 /**
92 * Assign this object to another (make this a copy of 'other').
93 * Use the 'assign' function to assign each element.
94 */
assign(const UVector & other,UTokenAssigner * assign,UErrorCode & ec)95 void UVector::assign(const UVector& other, UTokenAssigner *assign, UErrorCode &ec) {
96 if (ensureCapacity(other.count, ec)) {
97 setSize(other.count, ec);
98 if (U_SUCCESS(ec)) {
99 for (int32_t i=0; i<other.count; ++i) {
100 if (elements[i].pointer != 0 && deleter != 0) {
101 (*deleter)(elements[i].pointer);
102 }
103 (*assign)(&elements[i], &other.elements[i]);
104 }
105 }
106 }
107 }
108
109 // This only does something sensible if this object has a non-null comparer
operator ==(const UVector & other)110 UBool UVector::operator==(const UVector& other) {
111 int32_t i;
112 if (count != other.count) return FALSE;
113 if (comparer != NULL) {
114 // Compare using this object's comparer
115 for (i=0; i<count; ++i) {
116 if (!(*comparer)(elements[i], other.elements[i])) {
117 return FALSE;
118 }
119 }
120 }
121 return TRUE;
122 }
123
addElement(void * obj,UErrorCode & status)124 void UVector::addElement(void* obj, UErrorCode &status) {
125 if (ensureCapacity(count + 1, status)) {
126 elements[count++].pointer = obj;
127 }
128 }
129
addElement(int32_t elem,UErrorCode & status)130 void UVector::addElement(int32_t elem, UErrorCode &status) {
131 if (ensureCapacity(count + 1, status)) {
132 elements[count].pointer = NULL; // Pointers may be bigger than ints.
133 elements[count].integer = elem;
134 count++;
135 }
136 }
137
setElementAt(void * obj,int32_t index)138 void UVector::setElementAt(void* obj, int32_t index) {
139 if (0 <= index && index < count) {
140 if (elements[index].pointer != 0 && deleter != 0) {
141 (*deleter)(elements[index].pointer);
142 }
143 elements[index].pointer = obj;
144 }
145 /* else index out of range */
146 }
147
setElementAt(int32_t elem,int32_t index)148 void UVector::setElementAt(int32_t elem, int32_t index) {
149 if (0 <= index && index < count) {
150 if (elements[index].pointer != 0 && deleter != 0) {
151 // TODO: this should be an error. mixing up ints and pointers.
152 (*deleter)(elements[index].pointer);
153 }
154 elements[index].pointer = NULL;
155 elements[index].integer = elem;
156 }
157 /* else index out of range */
158 }
159
insertElementAt(void * obj,int32_t index,UErrorCode & status)160 void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) {
161 // must have 0 <= index <= count
162 if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
163 for (int32_t i=count; i>index; --i) {
164 elements[i] = elements[i-1];
165 }
166 elements[index].pointer = obj;
167 ++count;
168 }
169 /* else index out of range */
170 }
171
insertElementAt(int32_t elem,int32_t index,UErrorCode & status)172 void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
173 // must have 0 <= index <= count
174 if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
175 for (int32_t i=count; i>index; --i) {
176 elements[i] = elements[i-1];
177 }
178 elements[index].pointer = NULL;
179 elements[index].integer = elem;
180 ++count;
181 }
182 /* else index out of range */
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 != 0 && deleter != 0) {
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 != 0) {
253 for (int32_t i=0; i<count; ++i) {
254 if (elements[i].pointer != 0) {
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 == 0) {
269 for (i=0; i<count; i++) {
270 if (elements[i].pointer != other.elements[i].pointer) {
271 return FALSE;
272 }
273 }
274 } else {
275 UHashTok 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 UHashTok 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 UHashTok key;
296 key.integer = obj;
297 return indexOf(key, startIndex, HINT_KEY_INTEGER);
298 }
299
300 // This only works if this object has a non-null comparer
indexOf(UHashTok key,int32_t startIndex,int8_t hint) const301 int32_t UVector::indexOf(UHashTok key, int32_t startIndex, int8_t hint) const {
302 int32_t i;
303 if (comparer != 0) {
304 for (i=startIndex; i<count; ++i) {
305 if ((*comparer)(key, elements[i])) {
306 return i;
307 }
308 }
309 } else {
310 for (i=startIndex; i<count; ++i) {
311 /* Pointers are not always the same size as ints so to perform
312 * a valid comparision we need to know whether we are being
313 * provided an int or a pointer. */
314 if (hint & HINT_KEY_POINTER) {
315 if (key.pointer == elements[i].pointer) {
316 return i;
317 }
318 } else {
319 if (key.integer == elements[i].integer) {
320 return i;
321 }
322 }
323 }
324 }
325 return -1;
326 }
327
ensureCapacity(int32_t minimumCapacity,UErrorCode & status)328 UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
329 if (minimumCapacity < 0) {
330 status = U_ILLEGAL_ARGUMENT_ERROR;
331 return FALSE;
332 }
333 if (capacity < minimumCapacity) {
334 if (capacity > (INT32_MAX - 1) / 2) { // integer overflow check
335 status = U_ILLEGAL_ARGUMENT_ERROR;
336 return FALSE;
337 }
338 int32_t newCap = capacity * 2;
339 if (newCap < minimumCapacity) {
340 newCap = minimumCapacity;
341 }
342 if (newCap > (int32_t)(INT32_MAX / sizeof(UHashTok))) { // integer overflow check
343 // We keep the original memory contents on bad minimumCapacity.
344 status = U_ILLEGAL_ARGUMENT_ERROR;
345 return FALSE;
346 }
347 UHashTok* newElems = (UHashTok *)uprv_realloc(elements, sizeof(UHashTok)*newCap);
348 if (newElems == NULL) {
349 // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
350 status = U_MEMORY_ALLOCATION_ERROR;
351 return FALSE;
352 }
353 elements = newElems;
354 capacity = newCap;
355 }
356 return TRUE;
357 }
358
359 /**
360 * Change the size of this vector as follows: If newSize is smaller,
361 * then truncate the array, possibly deleting held elements for i >=
362 * newSize. If newSize is larger, grow the array, filling in new
363 * slots with NULL.
364 */
setSize(int32_t newSize,UErrorCode & status)365 void UVector::setSize(int32_t newSize, UErrorCode &status) {
366 int32_t i;
367 if (newSize < 0) {
368 return;
369 }
370 if (newSize > count) {
371 if (!ensureCapacity(newSize, status)) {
372 return;
373 }
374 UHashTok empty;
375 empty.pointer = NULL;
376 empty.integer = 0;
377 for (i=count; i<newSize; ++i) {
378 elements[i] = empty;
379 }
380 } else {
381 /* Most efficient to count down */
382 for (i=count-1; i>=newSize; --i) {
383 removeElementAt(i);
384 }
385 }
386 count = newSize;
387 }
388
389 /**
390 * Fill in the given array with all elements of this vector.
391 */
toArray(void ** result) const392 void** UVector::toArray(void** result) const {
393 void** a = result;
394 for (int i=0; i<count; ++i) {
395 *a++ = elements[i].pointer;
396 }
397 return result;
398 }
399
setDeleter(UObjectDeleter * d)400 UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
401 UObjectDeleter *old = deleter;
402 deleter = d;
403 return old;
404 }
405
setComparer(UKeyComparator * d)406 UKeyComparator *UVector::setComparer(UKeyComparator *d) {
407 UKeyComparator *old = comparer;
408 comparer = d;
409 return old;
410 }
411
412 /**
413 * Removes the element at the given index from this vector and
414 * transfer ownership of it to the caller. After this call, the
415 * caller owns the result and must delete it and the vector entry
416 * at 'index' is removed, shifting all subsequent entries back by
417 * one index and shortening the size of the vector by one. If the
418 * index is out of range or if there is no item at the given index
419 * then 0 is returned and the vector is unchanged.
420 */
orphanElementAt(int32_t index)421 void* UVector::orphanElementAt(int32_t index) {
422 void* e = 0;
423 if (0 <= index && index < count) {
424 e = elements[index].pointer;
425 for (int32_t i=index; i<count-1; ++i) {
426 elements[i] = elements[i+1];
427 }
428 --count;
429 }
430 /* else index out of range */
431 return e;
432 }
433
434 /**
435 * Insert the given object into this vector at its sorted position
436 * as defined by 'compare'. The current elements are assumed to
437 * be sorted already.
438 */
sortedInsert(void * obj,USortComparator * compare,UErrorCode & ec)439 void UVector::sortedInsert(void* obj, USortComparator *compare, UErrorCode& ec) {
440 UHashTok tok;
441 tok.pointer = obj;
442 sortedInsert(tok, compare, ec);
443 }
444
445 /**
446 * Insert the given integer into this vector at its sorted position
447 * as defined by 'compare'. The current elements are assumed to
448 * be sorted already.
449 */
sortedInsert(int32_t obj,USortComparator * compare,UErrorCode & ec)450 void UVector::sortedInsert(int32_t obj, USortComparator *compare, UErrorCode& ec) {
451 UHashTok tok;
452 tok.integer = obj;
453 sortedInsert(tok, compare, ec);
454 }
455
456 // ASSUME elements[] IS CURRENTLY SORTED
sortedInsert(UHashTok tok,USortComparator * compare,UErrorCode & ec)457 void UVector::sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& ec) {
458 // Perform a binary search for the location to insert tok at. Tok
459 // will be inserted between two elements a and b such that a <=
460 // tok && tok < b, where there is a 'virtual' elements[-1] always
461 // less than tok and a 'virtual' elements[count] always greater
462 // than tok.
463 int32_t min = 0, max = count;
464 while (min != max) {
465 int32_t probe = (min + max) / 2;
466 int8_t c = (*compare)(elements[probe], tok);
467 if (c > 0) {
468 max = probe;
469 } else {
470 // assert(c <= 0);
471 min = probe + 1;
472 }
473 }
474 if (ensureCapacity(count + 1, ec)) {
475 for (int32_t i=count; i>min; --i) {
476 elements[i] = elements[i-1];
477 }
478 elements[min] = tok;
479 ++count;
480 }
481 }
482
483 /**
484 * Array sort comparator function.
485 * Used from UVector::sort()
486 * Conforms to function signature required for uprv_sortArray().
487 * This function is essentially just a wrapper, to make a
488 * UVector style comparator function usable with uprv_sortArray().
489 *
490 * The context pointer to this function is a pointer back
491 * (with some extra indirection) to the user supplied comparator.
492 *
493 */
494 static int32_t U_CALLCONV
sortComparator(const void * context,const void * left,const void * right)495 sortComparator(const void *context, const void *left, const void *right) {
496 USortComparator *compare = *static_cast<USortComparator * const *>(context);
497 UHashTok tok1 = *static_cast<const UHashTok *>(left);
498 UHashTok tok2 = *static_cast<const UHashTok *>(right);
499 int32_t result = (*compare)(tok1, tok2);
500 return result;
501 }
502
503
504 /**
505 * Array sort comparison function for use from UVector::sorti()
506 * Compares int32_t vector elements.
507 */
508 static int32_t U_CALLCONV
sortiComparator(const void *,const void * left,const void * right)509 sortiComparator(const void * /*context */, const void *left, const void *right) {
510 const UHashTok *tok1 = static_cast<const UHashTok *>(left);
511 const UHashTok *tok2 = static_cast<const UHashTok *>(right);
512 int32_t result = tok1->integer < tok2->integer? -1 :
513 tok1->integer == tok2->integer? 0 : 1;
514 return result;
515 }
516
517 /**
518 * Sort the vector, assuming it constains ints.
519 * (A more general sort would take a comparison function, but it's
520 * not clear whether UVector's USortComparator or
521 * UComparator from uprv_sortAray would be more appropriate.)
522 */
sorti(UErrorCode & ec)523 void UVector::sorti(UErrorCode &ec) {
524 if (U_SUCCESS(ec)) {
525 uprv_sortArray(elements, count, sizeof(UHashTok),
526 sortiComparator, NULL, FALSE, &ec);
527 }
528 }
529
530
531 /**
532 * Sort with a user supplied comparator.
533 *
534 * The comparator function handling is confusing because the function type
535 * for UVector (as defined for sortedInsert()) is different from the signature
536 * required by uprv_sortArray(). This is handled by passing the
537 * the UVector sort function pointer via the context pointer to a
538 * sortArray() comparator function, which can then call back to
539 * the original user functtion.
540 *
541 * An additional twist is that it's not safe to pass a pointer-to-function
542 * as a (void *) data pointer, so instead we pass a (data) pointer to a
543 * pointer-to-function variable.
544 */
sort(USortComparator * compare,UErrorCode & ec)545 void UVector::sort(USortComparator *compare, UErrorCode &ec) {
546 if (U_SUCCESS(ec)) {
547 uprv_sortArray(elements, count, sizeof(UHashTok),
548 sortComparator, &compare, FALSE, &ec);
549 }
550 }
551
552
553 /**
554 * Sort with a user supplied comparator of type UComparator.
555 */
sortWithUComparator(UComparator * compare,const void * context,UErrorCode & ec)556 void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
557 if (U_SUCCESS(ec)) {
558 uprv_sortArray(elements, count, sizeof(UHashTok),
559 compare, context, FALSE, &ec);
560 }
561 }
562
563 U_NAMESPACE_END
564
565