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(NULL)
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
83UBool 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(void) {
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 == 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
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 == 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 */
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