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-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ******************************************************************************
8 */
9 
10 #include "uvectr64.h"
11 #include "cmemory.h"
12 #include "putilimp.h"
13 
14 U_NAMESPACE_BEGIN
15 
16 #define DEFAULT_CAPACITY 8
17 
18 /*
19  * Constants for hinting whether a key is an integer
20  * or a pointer.  If a hint bit is zero, then the associated
21  * token is assumed to be an integer. This is needed for iSeries
22  */
23 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64)24 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64)
25 
26 UVector64::UVector64(UErrorCode &status) :
27     count(0),
28     capacity(0),
29     maxCapacity(0),
30     elements(NULL)
31 {
32     _init(DEFAULT_CAPACITY, status);
33 }
34 
UVector64(int32_t initialCapacity,UErrorCode & status)35 UVector64::UVector64(int32_t initialCapacity, UErrorCode &status) :
36     count(0),
37     capacity(0),
38     maxCapacity(0),
39     elements(0)
40 {
41     _init(initialCapacity, status);
42 }
43 
44 
45 
_init(int32_t initialCapacity,UErrorCode & status)46 void UVector64::_init(int32_t initialCapacity, UErrorCode &status) {
47     // Fix bogus initialCapacity values; avoid malloc(0)
48     if (initialCapacity < 1) {
49         initialCapacity = DEFAULT_CAPACITY;
50     }
51     if (maxCapacity>0 && maxCapacity<initialCapacity) {
52         initialCapacity = maxCapacity;
53     }
54     if (initialCapacity > (int32_t)(INT32_MAX / sizeof(int64_t))) {
55         initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
56     }
57     elements = (int64_t *)uprv_malloc(sizeof(int64_t)*initialCapacity);
58     if (elements == 0) {
59         status = U_MEMORY_ALLOCATION_ERROR;
60     } else {
61         capacity = initialCapacity;
62     }
63 }
64 
~UVector64()65 UVector64::~UVector64() {
66     uprv_free(elements);
67     elements = 0;
68 }
69 
70 /**
71  * Assign this object to another (make this a copy of 'other').
72  */
assign(const UVector64 & other,UErrorCode & ec)73 void UVector64::assign(const UVector64& other, UErrorCode &ec) {
74     if (ensureCapacity(other.count, ec)) {
75         setSize(other.count);
76         for (int32_t i=0; i<other.count; ++i) {
77             elements[i] = other.elements[i];
78         }
79     }
80 }
81 
82 
operator ==(const UVector64 & other)83 UBool UVector64::operator==(const UVector64& other) {
84     int32_t i;
85     if (count != other.count) return FALSE;
86     for (i=0; i<count; ++i) {
87         if (elements[i] != other.elements[i]) {
88             return FALSE;
89         }
90     }
91     return TRUE;
92 }
93 
94 
setElementAt(int64_t elem,int32_t index)95 void UVector64::setElementAt(int64_t elem, int32_t index) {
96     if (0 <= index && index < count) {
97         elements[index] = elem;
98     }
99     /* else index out of range */
100 }
101 
insertElementAt(int64_t elem,int32_t index,UErrorCode & status)102 void UVector64::insertElementAt(int64_t elem, int32_t index, UErrorCode &status) {
103     // must have 0 <= index <= count
104     if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
105         for (int32_t i=count; i>index; --i) {
106             elements[i] = elements[i-1];
107         }
108         elements[index] = elem;
109         ++count;
110     }
111     /* else index out of range */
112 }
113 
removeAllElements(void)114 void UVector64::removeAllElements(void) {
115     count = 0;
116 }
117 
expandCapacity(int32_t minimumCapacity,UErrorCode & status)118 UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
119     if (U_FAILURE(status)) {
120         return FALSE;
121     }
122     if (minimumCapacity < 0) {
123         status = U_ILLEGAL_ARGUMENT_ERROR;
124         return FALSE;
125     }
126     if (capacity >= minimumCapacity) {
127         return TRUE;
128     }
129     if (maxCapacity>0 && minimumCapacity>maxCapacity) {
130         status = U_BUFFER_OVERFLOW_ERROR;
131         return FALSE;
132     }
133     if (capacity > (INT32_MAX - 1) / 2) {  // integer overflow check
134         status = U_ILLEGAL_ARGUMENT_ERROR;
135         return FALSE;
136     }
137     int32_t newCap = capacity * 2;
138     if (newCap < minimumCapacity) {
139         newCap = minimumCapacity;
140     }
141     if (maxCapacity > 0 && newCap > maxCapacity) {
142         newCap = maxCapacity;
143     }
144     if (newCap > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check
145         // We keep the original memory contents on bad minimumCapacity/maxCapacity.
146         status = U_ILLEGAL_ARGUMENT_ERROR;
147         return FALSE;
148     }
149     int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap);
150     if (newElems == NULL) {
151         // We keep the original contents on the memory failure on realloc.
152         status = U_MEMORY_ALLOCATION_ERROR;
153         return FALSE;
154     }
155     elements = newElems;
156     capacity = newCap;
157     return TRUE;
158 }
159 
setMaxCapacity(int32_t limit)160 void UVector64::setMaxCapacity(int32_t limit) {
161     U_ASSERT(limit >= 0);
162     if (limit < 0) {
163         limit = 0;
164     }
165     if (limit > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check for realloc
166         //  Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged
167         return;
168     }
169     maxCapacity = limit;
170     if (capacity <= maxCapacity || maxCapacity == 0) {
171         // Current capacity is within the new limit.
172         return;
173     }
174 
175     // New maximum capacity is smaller than the current size.
176     // Realloc the storage to the new, smaller size.
177     int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*maxCapacity);
178     if (newElems == NULL) {
179         // Realloc to smaller failed.
180         //   Just keep what we had.  No need to call it a failure.
181         return;
182     }
183     elements = newElems;
184     capacity = maxCapacity;
185     if (count > capacity) {
186         count = capacity;
187     }
188 }
189 
190 /**
191  * Change the size of this vector as follows: If newSize is smaller,
192  * then truncate the array, possibly deleting held elements for i >=
193  * newSize.  If newSize is larger, grow the array, filling in new
194  * slots with NULL.
195  */
setSize(int32_t newSize)196 void UVector64::setSize(int32_t newSize) {
197     int32_t i;
198     if (newSize < 0) {
199         return;
200     }
201     if (newSize > count) {
202         UErrorCode ec = U_ZERO_ERROR;
203         if (!ensureCapacity(newSize, ec)) {
204             return;
205         }
206         for (i=count; i<newSize; ++i) {
207             elements[i] = 0;
208         }
209     }
210     count = newSize;
211 }
212 
213 U_NAMESPACE_END
214 
215