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
14U_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
24UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64)
25
26UVector64::UVector64(UErrorCode &status) :
27 count(0),
28 capacity(0),
29 maxCapacity(0),
30 elements(nullptr)
31{
32 _init(DEFAULT_CAPACITY, status);
33}
34
35UVector64::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
46void 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
65UVector64::~UVector64() {
66 uprv_free(elements);
67 elements = 0;
68}
69
70/**
71 * Assign this object to another (make this a copy of 'other').
72 */
73void 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
83bool 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
95void 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
102void 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
114void UVector64::removeAllElements() {
115 count = 0;
116}
117
118UBool 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 == nullptr) {
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
160void 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 == nullptr) {
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 nullptr.
195 */
196void 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
213U_NAMESPACE_END
214
215