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
CharString(CharString && src)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
operator =(CharString && src)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
copyFrom(const CharString & s,UErrorCode & errorCode)38 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
39 if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
40 len=s.len;
41 uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
42 }
43 return *this;
44 }
45
lastIndexOf(char c) const46 int32_t CharString::lastIndexOf(char c) const {
47 for(int32_t i=len; i>0;) {
48 if(buffer[--i]==c) {
49 return i;
50 }
51 }
52 return -1;
53 }
54
truncate(int32_t newLength)55 CharString &CharString::truncate(int32_t newLength) {
56 if(newLength<0) {
57 newLength=0;
58 }
59 if(newLength<len) {
60 buffer[len=newLength]=0;
61 }
62 return *this;
63 }
64
append(char c,UErrorCode & errorCode)65 CharString &CharString::append(char c, UErrorCode &errorCode) {
66 if(ensureCapacity(len+2, 0, errorCode)) {
67 buffer[len++]=c;
68 buffer[len]=0;
69 }
70 return *this;
71 }
72
append(const char * s,int32_t sLength,UErrorCode & errorCode)73 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
74 if(U_FAILURE(errorCode)) {
75 return *this;
76 }
77 if(sLength<-1 || (s==NULL && sLength!=0)) {
78 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
79 return *this;
80 }
81 if(sLength<0) {
82 sLength= static_cast<int32_t>(uprv_strlen(s));
83 }
84 if(sLength>0) {
85 if(s==(buffer.getAlias()+len)) {
86 // The caller wrote into the getAppendBuffer().
87 if(sLength>=(buffer.getCapacity()-len)) {
88 // The caller wrote too much.
89 errorCode=U_INTERNAL_PROGRAM_ERROR;
90 } else {
91 buffer[len+=sLength]=0;
92 }
93 } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
94 sLength>=(buffer.getCapacity()-len)
95 ) {
96 // (Part of) this string is appended to itself which requires reallocation,
97 // so we have to make a copy of the substring and append that.
98 return append(CharString(s, sLength, errorCode), errorCode);
99 } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
100 uprv_memcpy(buffer.getAlias()+len, s, sLength);
101 buffer[len+=sLength]=0;
102 }
103 }
104 return *this;
105 }
106
getAppendBuffer(int32_t minCapacity,int32_t desiredCapacityHint,int32_t & resultCapacity,UErrorCode & errorCode)107 char *CharString::getAppendBuffer(int32_t minCapacity,
108 int32_t desiredCapacityHint,
109 int32_t &resultCapacity,
110 UErrorCode &errorCode) {
111 if(U_FAILURE(errorCode)) {
112 resultCapacity=0;
113 return NULL;
114 }
115 int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
116 if(appendCapacity>=minCapacity) {
117 resultCapacity=appendCapacity;
118 return buffer.getAlias()+len;
119 }
120 if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
121 resultCapacity=buffer.getCapacity()-len-1;
122 return buffer.getAlias()+len;
123 }
124 resultCapacity=0;
125 return NULL;
126 }
127
appendInvariantChars(const UnicodeString & s,UErrorCode & errorCode)128 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
129 return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
130 }
131
appendInvariantChars(const UChar * uchars,int32_t ucharsLen,UErrorCode & errorCode)132 CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
133 if(U_FAILURE(errorCode)) {
134 return *this;
135 }
136 if (!uprv_isInvariantUString(uchars, ucharsLen)) {
137 errorCode = U_INVARIANT_CONVERSION_ERROR;
138 return *this;
139 }
140 if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
141 u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
142 len += ucharsLen;
143 buffer[len] = 0;
144 }
145 return *this;
146 }
147
ensureCapacity(int32_t capacity,int32_t desiredCapacityHint,UErrorCode & errorCode)148 UBool CharString::ensureCapacity(int32_t capacity,
149 int32_t desiredCapacityHint,
150 UErrorCode &errorCode) {
151 if(U_FAILURE(errorCode)) {
152 return FALSE;
153 }
154 if(capacity>buffer.getCapacity()) {
155 if(desiredCapacityHint==0) {
156 desiredCapacityHint=capacity+buffer.getCapacity();
157 }
158 if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
159 buffer.resize(capacity, len+1)==NULL
160 ) {
161 errorCode=U_MEMORY_ALLOCATION_ERROR;
162 return FALSE;
163 }
164 }
165 return TRUE;
166 }
167
appendPathPart(StringPiece s,UErrorCode & errorCode)168 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
169 if(U_FAILURE(errorCode)) {
170 return *this;
171 }
172 if(s.length()==0) {
173 return *this;
174 }
175 char c;
176 if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
177 append(U_FILE_SEP_CHAR, errorCode);
178 }
179 append(s, errorCode);
180 return *this;
181 }
182
ensureEndsWithFileSeparator(UErrorCode & errorCode)183 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
184 char c;
185 if(U_SUCCESS(errorCode) && len>0 &&
186 (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
187 append(U_FILE_SEP_CHAR, errorCode);
188 }
189 return *this;
190 }
191
192 U_NAMESPACE_END
193