Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/icu4c/common/charstr.cpp
9903 views
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
* Copyright (C) 2010-2015, International Business Machines
6
* Corporation and others. All Rights Reserved.
7
*******************************************************************************
8
* file name: charstr.cpp
9
* encoding: UTF-8
10
* tab size: 8 (not used)
11
* indentation:4
12
*
13
* created on: 2010may19
14
* created by: Markus W. Scherer
15
*/
16
17
#include <cstdlib>
18
19
#include "unicode/utypes.h"
20
#include "unicode/putil.h"
21
#include "charstr.h"
22
#include "cmemory.h"
23
#include "cstring.h"
24
#include "uinvchar.h"
25
#include "ustr_imp.h"
26
27
U_NAMESPACE_BEGIN
28
29
CharString::CharString(CharString&& src) noexcept
30
: buffer(std::move(src.buffer)), len(src.len) {
31
src.len = 0; // not strictly necessary because we make no guarantees on the source string
32
}
33
34
CharString& CharString::operator=(CharString&& src) noexcept {
35
buffer = std::move(src.buffer);
36
len = src.len;
37
src.len = 0; // not strictly necessary because we make no guarantees on the source string
38
return *this;
39
}
40
41
char *CharString::cloneData(UErrorCode &errorCode) const {
42
if (U_FAILURE(errorCode)) { return nullptr; }
43
char *p = static_cast<char *>(uprv_malloc(len + 1));
44
if (p == nullptr) {
45
errorCode = U_MEMORY_ALLOCATION_ERROR;
46
return nullptr;
47
}
48
uprv_memcpy(p, buffer.getAlias(), len + 1);
49
return p;
50
}
51
52
int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
53
if (U_FAILURE(errorCode)) { return len; }
54
if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
55
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
56
return len;
57
}
58
const char *src = buffer.getAlias();
59
if (0 < len && len <= capacity && src != dest) {
60
uprv_memcpy(dest, src, len);
61
}
62
return u_terminateChars(dest, capacity, len, &errorCode);
63
}
64
65
CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
66
if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
67
len=s.len;
68
uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
69
}
70
return *this;
71
}
72
73
CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
74
if (U_FAILURE(errorCode)) {
75
return *this;
76
}
77
len = 0;
78
append(s, errorCode);
79
return *this;
80
}
81
82
int32_t CharString::lastIndexOf(char c) const {
83
for(int32_t i=len; i>0;) {
84
if(buffer[--i]==c) {
85
return i;
86
}
87
}
88
return -1;
89
}
90
91
bool CharString::contains(StringPiece s) const {
92
if (s.empty()) { return false; }
93
const char *p = buffer.getAlias();
94
int32_t lastStart = len - s.length();
95
for (int32_t i = 0; i <= lastStart; ++i) {
96
if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
97
return true;
98
}
99
}
100
return false;
101
}
102
103
CharString &CharString::truncate(int32_t newLength) {
104
if(newLength<0) {
105
newLength=0;
106
}
107
if(newLength<len) {
108
buffer[len=newLength]=0;
109
}
110
return *this;
111
}
112
113
CharString &CharString::append(char c, UErrorCode &errorCode) {
114
if(ensureCapacity(len+2, 0, errorCode)) {
115
buffer[len++]=c;
116
buffer[len]=0;
117
}
118
return *this;
119
}
120
121
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
122
if(U_FAILURE(errorCode)) {
123
return *this;
124
}
125
if(sLength<-1 || (s==nullptr && sLength!=0)) {
126
errorCode=U_ILLEGAL_ARGUMENT_ERROR;
127
return *this;
128
}
129
if(sLength<0) {
130
sLength= static_cast<int32_t>(uprv_strlen(s));
131
}
132
if(sLength>0) {
133
if(s==(buffer.getAlias()+len)) {
134
// The caller wrote into the getAppendBuffer().
135
if(sLength>=(buffer.getCapacity()-len)) {
136
// The caller wrote too much.
137
errorCode=U_INTERNAL_PROGRAM_ERROR;
138
} else {
139
buffer[len+=sLength]=0;
140
}
141
} else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
142
sLength>=(buffer.getCapacity()-len)
143
) {
144
// (Part of) this string is appended to itself which requires reallocation,
145
// so we have to make a copy of the substring and append that.
146
return append(CharString(s, sLength, errorCode), errorCode);
147
} else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
148
uprv_memcpy(buffer.getAlias()+len, s, sLength);
149
buffer[len+=sLength]=0;
150
}
151
}
152
return *this;
153
}
154
155
CharString &CharString::appendNumber(int64_t number, UErrorCode &status) {
156
if (number < 0) {
157
this->append('-', status);
158
if (U_FAILURE(status)) {
159
return *this;
160
}
161
}
162
163
if (number == 0) {
164
this->append('0', status);
165
return *this;
166
}
167
168
int32_t numLen = 0;
169
while (number != 0) {
170
int32_t residue = number % 10;
171
number /= 10;
172
this->append(std::abs(residue) + '0', status);
173
numLen++;
174
if (U_FAILURE(status)) {
175
return *this;
176
}
177
}
178
179
int32_t start = this->length() - numLen, end = this->length() - 1;
180
while(start < end) {
181
std::swap(this->data()[start++], this->data()[end--]);
182
}
183
184
return *this;
185
}
186
187
char *CharString::getAppendBuffer(int32_t minCapacity,
188
int32_t desiredCapacityHint,
189
int32_t &resultCapacity,
190
UErrorCode &errorCode) {
191
if(U_FAILURE(errorCode)) {
192
resultCapacity=0;
193
return nullptr;
194
}
195
int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
196
if(appendCapacity>=minCapacity) {
197
resultCapacity=appendCapacity;
198
return buffer.getAlias()+len;
199
}
200
if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
201
resultCapacity=buffer.getCapacity()-len-1;
202
return buffer.getAlias()+len;
203
}
204
resultCapacity=0;
205
return nullptr;
206
}
207
208
CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
209
return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
210
}
211
212
CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
213
if(U_FAILURE(errorCode)) {
214
return *this;
215
}
216
if (!uprv_isInvariantUString(uchars, ucharsLen)) {
217
errorCode = U_INVARIANT_CONVERSION_ERROR;
218
return *this;
219
}
220
if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
221
u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
222
len += ucharsLen;
223
buffer[len] = 0;
224
}
225
return *this;
226
}
227
228
UBool CharString::ensureCapacity(int32_t capacity,
229
int32_t desiredCapacityHint,
230
UErrorCode &errorCode) {
231
if(U_FAILURE(errorCode)) {
232
return false;
233
}
234
if(capacity>buffer.getCapacity()) {
235
if(desiredCapacityHint==0) {
236
desiredCapacityHint=capacity+buffer.getCapacity();
237
}
238
if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
239
buffer.resize(capacity, len+1)==nullptr
240
) {
241
errorCode=U_MEMORY_ALLOCATION_ERROR;
242
return false;
243
}
244
}
245
return true;
246
}
247
248
CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
249
if(U_FAILURE(errorCode)) {
250
return *this;
251
}
252
if(s.length()==0) {
253
return *this;
254
}
255
char c;
256
if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
257
append(getDirSepChar(), errorCode);
258
}
259
append(s, errorCode);
260
return *this;
261
}
262
263
CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
264
char c;
265
if(U_SUCCESS(errorCode) && len>0 &&
266
(c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
267
append(getDirSepChar(), errorCode);
268
}
269
return *this;
270
}
271
272
char CharString::getDirSepChar() const {
273
char dirSepChar = U_FILE_SEP_CHAR;
274
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
275
// We may need to return a different directory separator when building for Cygwin or MSYS2.
276
if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
277
dirSepChar = U_FILE_ALT_SEP_CHAR;
278
#endif
279
return dirSepChar;
280
}
281
282
U_NAMESPACE_END
283
284