]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/charstr.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / common / charstr.cpp
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 "unicode/utypes.h"
18 #include "unicode/putil.h"
19 #include "charstr.h"
20 #include "cmemory.h"
21 #include "cstring.h"
22 #include "uinvchar.h"
23
24 U_NAMESPACE_BEGIN
25
26 CharString::CharString(CharString&& src) U_NOEXCEPT
27 : buffer(std::move(src.buffer)), len(src.len) {
28 src.len = 0; // not strictly necessary because we make no guarantees on the source string
29 }
30
31 CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
32 buffer = std::move(src.buffer);
33 len = src.len;
34 src.len = 0; // not strictly necessary because we make no guarantees on the source string
35 return *this;
36 }
37
38 char *CharString::cloneData(UErrorCode &errorCode) const {
39 if (U_FAILURE(errorCode)) { return nullptr; }
40 char *p = static_cast<char *>(uprv_malloc(len + 1));
41 if (p == nullptr) {
42 errorCode = U_MEMORY_ALLOCATION_ERROR;
43 return nullptr;
44 }
45 uprv_memcpy(p, buffer.getAlias(), len + 1);
46 return p;
47 }
48
49 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
50 if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
51 len=s.len;
52 uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
53 }
54 return *this;
55 }
56
57 int32_t CharString::lastIndexOf(char c) const {
58 for(int32_t i=len; i>0;) {
59 if(buffer[--i]==c) {
60 return i;
61 }
62 }
63 return -1;
64 }
65
66 bool CharString::contains(StringPiece s) const {
67 if (s.empty()) { return false; }
68 const char *p = buffer.getAlias();
69 int32_t lastStart = len - s.length();
70 for (int32_t i = 0; i <= lastStart; ++i) {
71 if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
72 return true;
73 }
74 }
75 return false;
76 }
77
78 CharString &CharString::truncate(int32_t newLength) {
79 if(newLength<0) {
80 newLength=0;
81 }
82 if(newLength<len) {
83 buffer[len=newLength]=0;
84 }
85 return *this;
86 }
87
88 CharString &CharString::append(char c, UErrorCode &errorCode) {
89 if(ensureCapacity(len+2, 0, errorCode)) {
90 buffer[len++]=c;
91 buffer[len]=0;
92 }
93 return *this;
94 }
95
96 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
97 if(U_FAILURE(errorCode)) {
98 return *this;
99 }
100 if(sLength<-1 || (s==NULL && sLength!=0)) {
101 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
102 return *this;
103 }
104 if(sLength<0) {
105 sLength= static_cast<int32_t>(uprv_strlen(s));
106 }
107 if(sLength>0) {
108 if(s==(buffer.getAlias()+len)) {
109 // The caller wrote into the getAppendBuffer().
110 if(sLength>=(buffer.getCapacity()-len)) {
111 // The caller wrote too much.
112 errorCode=U_INTERNAL_PROGRAM_ERROR;
113 } else {
114 buffer[len+=sLength]=0;
115 }
116 } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
117 sLength>=(buffer.getCapacity()-len)
118 ) {
119 // (Part of) this string is appended to itself which requires reallocation,
120 // so we have to make a copy of the substring and append that.
121 return append(CharString(s, sLength, errorCode), errorCode);
122 } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
123 uprv_memcpy(buffer.getAlias()+len, s, sLength);
124 buffer[len+=sLength]=0;
125 }
126 }
127 return *this;
128 }
129
130 char *CharString::getAppendBuffer(int32_t minCapacity,
131 int32_t desiredCapacityHint,
132 int32_t &resultCapacity,
133 UErrorCode &errorCode) {
134 if(U_FAILURE(errorCode)) {
135 resultCapacity=0;
136 return NULL;
137 }
138 int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
139 if(appendCapacity>=minCapacity) {
140 resultCapacity=appendCapacity;
141 return buffer.getAlias()+len;
142 }
143 if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
144 resultCapacity=buffer.getCapacity()-len-1;
145 return buffer.getAlias()+len;
146 }
147 resultCapacity=0;
148 return NULL;
149 }
150
151 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
152 return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
153 }
154
155 CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
156 if(U_FAILURE(errorCode)) {
157 return *this;
158 }
159 if (!uprv_isInvariantUString(uchars, ucharsLen)) {
160 errorCode = U_INVARIANT_CONVERSION_ERROR;
161 return *this;
162 }
163 if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
164 u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
165 len += ucharsLen;
166 buffer[len] = 0;
167 }
168 return *this;
169 }
170
171 UBool CharString::ensureCapacity(int32_t capacity,
172 int32_t desiredCapacityHint,
173 UErrorCode &errorCode) {
174 if(U_FAILURE(errorCode)) {
175 return FALSE;
176 }
177 if(capacity>buffer.getCapacity()) {
178 if(desiredCapacityHint==0) {
179 desiredCapacityHint=capacity+buffer.getCapacity();
180 }
181 if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
182 buffer.resize(capacity, len+1)==NULL
183 ) {
184 errorCode=U_MEMORY_ALLOCATION_ERROR;
185 return FALSE;
186 }
187 }
188 return TRUE;
189 }
190
191 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
192 if(U_FAILURE(errorCode)) {
193 return *this;
194 }
195 if(s.length()==0) {
196 return *this;
197 }
198 char c;
199 if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
200 append(U_FILE_SEP_CHAR, errorCode);
201 }
202 append(s, errorCode);
203 return *this;
204 }
205
206 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
207 char c;
208 if(U_SUCCESS(errorCode) && len>0 &&
209 (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
210 append(U_FILE_SEP_CHAR, errorCode);
211 }
212 return *this;
213 }
214
215 U_NAMESPACE_END